线程同步之信号量
一、线程限号量的概念
信号量的本质是一个非负整数计数器,是共享资源的数目,通常被用来控制对共享资源的访问信号量可以实现线程的同步和互斥,通过sem_post()和sem_wait()函数对信号量 进行加减操作从而解决线程的同步和互斥
二、信号量的相关函数
信号量数据类型:sem_t
#include<semaphore.h>
int sem_init(sem_t *sem,int pshared,unsigned value);
该函数用于创建信号量。初始化一个定位在sem的匿名信号量。value参数指定信号量的初始值。pshared参数指明信号量是由进程内线程共享,还是由进程之间共享。如果pshared的值为0,那么信号量将被进程内的线程共享,并且应该放置在所有线程都可见的地址上(如全局变量,或者堆上动态分配的变量)。
int sem_destory(sem_t *sem);
返回:成功返回0,出错返回错误编号
参数:
sem信号量指针
pthread是否在进程间共享的标志,0为不共享,1为共享
value初始的时候信号量值
该函数用于对用完的信号量的清理。用来释放信号量sem。
int sem_post(sem_t *sem);
功能:增加信号量的值
该函数用于以原子操作的方式将信号量的值加1。用来增加信号量的值当有线程阻塞在这个信号量上时,调用这个函数会使其中的一个线程不再阻塞,选择机制同样是由线程的调度策略决定的。它信号量的值加1同时发出信号来唤醒等待的线程。
int sem_wait(sem_t *sem);
功能:减少信号量的值
该函数用于以原子操作的方式将信号量的值减1。(原子操作就是,如果两个线程企图同时给一个信号量加1或减1,它们之间不会互相干扰。)但它永远会先等待该信号量为一个非零值才开始做减法。也就是说,如果你对一个值为2的信号量调用sem_wait(),线程将会继续执行,这信号量的值将减到1。如果对一个值为0的信号量调用sem_wait(),这个函数就会等待直到有其它线程增加了这个值使它不再是0为止。如果有两个线程都在sem_wait()中等待同一个信号量变成非零值,那么当它被第三个线程增加一个“1”时,等待线程中只有一个能够对信号量做减法并继续执行,另一个还将处于等待状态。被用来阻塞当前线程直到信号量sem的值大于0,解除阻塞后将sem的值减一,表明公共资源经使用后减少。
int sem_trywait(sem_t *sem);
功能:sem_wait()的非阻塞版本
返回:0成功,出错返回错误编码
注意:
调用:sem_post()一次信号量作加1操作
调用sem_wait()一次信号量减1操作
当线程调用sem_wait后,若信号量的值小于0,则线程阻塞,只有其它线程在调用sem_post对信号量做加操作后并且其值大于或者等于0的时候,阻塞的线程才能继续运行;
例子:
1.最简单的一个例子来说明一下sem的使用
1 #include<stdio.h>
2 #include<semaphore.h>
3 #include<stdlib.h>
4 #include<unistd.h>
5 #include<pthread.h>
6
7 sem_t sem;
8
9 void* test(void* arg)
10 {
11 while(1)
12 {
13 sem_wait(&sem);
14 printf("hello sem!!!\n");
15 }
16 }
17
18 int main()
19 {
20
21 pthread_t tid;
22 sem_init(&sem,0,0);//繁忙
23 pthread_create(&tid,NULL,test,NULL);
24
25 while(1)
26 {
27 sem_post(&sem);//+1
28 sleep(2);
29 }
30 return 0;
31 }
结果:
wz@wz-machine:~/linux$ ./sem1
hello sem!!!
hello sem!!!
hello sem!!!
hello sem!!!
每隔2秒打印一个hello sem,刚开始是初始化信号量为0,等到+1后,就开始打印。