信号量
此处只涉及利用“二进制信号量”(只用0和1)完成“控制线程顺序”为中心的同步方法。
信号量的创建和销毁函数:
pshared参数超出我们关注的范围,默认向其传递0.
信号量相当于互斥量lock,unlock的函数:
调用sem_init函数时,操作系统将创建信号量对象,此对象中记录着“信号量值”整数。该值在调用sem_post函数时增1,调用sem_wait函数时减1。信号量的值不能小于0,当信号量为0的情况下调用sem_wait函数时,调用函数的线程将进入阻塞状态。此时如果有其它线程调用sem_post函数,信号量的值将变为1,而原来阻塞的线程可以将该信号量重新减为0并跳出阻塞状态。
实际上就是通过这种特性完成临界区的同步操作,通过如下形式同步临界区:
- sem_wait(&sem); //信号量变为0...
- //临界区的开始
- //.........
- //临界区的结束
- sem_post(&sem); //信号量变为1
上述代码中,调用sem_wait函数进入临界区的线程在调用sem_post函数前不允许其它线程进入临界区。
信号量的值在0和1之间跳转,因此,具有这种特性的机制称为”二进制信号量“。
示例:线程A从输入得到值后存入全局变量num,此时线程B将取走该值并累加。该过程共进行5次,完成后输出总和并退出
- /* 控制访问顺序的线程同步 */
- #include<stdio.h>
- #include<pthread.h>
- #include<semaphore.h>
- void * read(void * arg);
- void * accu(void * arg);
- static sem_t sem_one;
- static sem_t sem_two;
- static int num;
- int main(int argc, char *argv[])
- {
- pthread_t id_t1,id_t2;
- sem_init(&sem_one,0,0); //sem_one初始值为0
- sem_init(&sem_two,0,1); //sem_two初始值为1
- pthread_create(&id_t1,NULL,read,NULL);
- pthread_create(&id_t2,NULL,accu,NULL);
- pthread_join(id_t1,NULL);
- pthread_join(id_t2,NULL);
- sem_destroy(&sem_one);
- sem_destroy(&sem_two);
- return 0;
- }
- void * read(void * arg)
- {
- int i;
- for(i=0; i<5; i++)
- {
- fputs("Input num: ",stdout);
- sem_wait(&sem_two); //初始值为1,调用sem_wait,sem_two变为0; 阻塞,在accu中加1后跳出阻塞状态
- scanf("%d",&num);
- sem_post(&sem_one); //sem_one变为1
- }
- return NULL;
- }
- void * accu(void * arg)
- {
- int sum=0, i;
- for(i=0; i<5; i++)
- {
- sem_wait(&sem_one); //sem_one变为0,阻塞,在read中加1后跳出阻塞状态
- sum+=num;
- sem_post(&sem_two); //sem_two变为1
- }
- printf("Result: %d \n",sum);
- return NULL;
- }
15,16行生成两个信号量。掌握需要2个信号量的原因。
运行结果: