3. linux 线程同步(二)

信号量

信号量是互斥锁的升级版把互斥锁中1变成了n,举个简单的例子:假设现在有10个人,有一部手机,这10个人都竞争来使用手机打电话这就是互斥锁。对于信号量,现在可能是有4部手机,这10个人都竞争来使用手机打电话。相比互斥锁信号量由1变成了4。信号量相也就是操作系统中pv操作,它广泛应用进程或者线程间的同步与互斥。

相关库函数介绍

[cpp]  view plain  copy
  1. #include <semaphore.h>//所需头文件  
  2. //初始化信号量sem初始化的时候可以指定信号量的初始值,以及是否可以在多进程间共享value表示要信号量初始值,pshared表示是否再多进程之前共享。0表示不在多进程间  
  3. 共享,非0表示在多进程之间共享具体可以man sem_init  
  4. //成功返回0,出错返回-1  
  5. int sem_init(sem_t *sem, int pshared, unsigned int value);    
  6. int sem_wait(sem_t *sem)//相当于p操作  
  7. int sem_try_wait(sem_t *sem)//相当于p操作,在信号量值大于0时都能将信号量的值减一,与上面sem_wait的区别是,在信号值小于0时  
  8. int sem_post(sem_t *sem)//相当于v操作  
  9. int sem_getvalue(sem_t *sem)//用于得到信号量的值  
  10. int sem_destory(sem_t *sem) //释放信号量  
  11.    

信号量实例:生产者消费值

[cpp]  view plain  copy
  1. #include<stdio.h>  
  2. #include<stdlib.h>  
  3. #include <pthread.h>  
  4. #include <semaphore.h>  
  5. #define BUFSIZE  10  
  6. int buf[BUFSIZE];  
  7. sem_t consumer_sem,producer_sem;  
  8. void *consumer(void *arg)  
  9. {  
  10.     int c=0;  
  11.     while(1)  
  12.     {  
  13.         sem_wait(&consumer_sem);//开始消费consumer_sem值减一  
  14.         printf("consumer %d: %d\n",c,buf[c]);//消费数据  
  15.         c++;  
  16.         c=c%BUFSIZE;  
  17.         sleep(1);//睡眠1s  
  18.         sem_post(&producer_sem);//producer_sem值加1  
  19.     }  
  20. }  
  21. void *producer(void *arg)  
  22. {  
  23.     int p=0;  
  24.     while(1)  
  25.     {  
  26.         sem_wait(&producer_sem);//开始生产producer_sem值减一  
  27.         buf[p]=rand() % 1000 + 1;//生产数据  
  28.         printf("producer %d: %d\n",p,buf[p]);  
  29.         p++;  
  30.         p=p%BUFSIZE;  
  31.         sem_post(&consumer_sem);//consumer_sem值加1  
  32.           
  33.     }  
  34. }  
  35.   
  36.   
  37. int main()  
  38. {  
  39.       
  40.     sem_init(&consumer_sem,0,0);  
  41.     sem_init(&producer_sem,0,BUFSIZE);  
  42.       
  43.     pthread_t pid,cid;  
  44.     pthread_create(&pid,NULL,producer,NULL);  
  45.     pthread_create(&cid,NULL,consumer,NULL);  
  46.   
  47.     pthread_join(pid, NULL);  
  48.     pthread_join(cid, NULL);  
  49.     sem_destroy(&consumer_sem);  
  50.     sem_destroy(&producer_sem);  
  51.     return 0;  
  52.       
  53. }  


条件变量

条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待"条件变量的条件成立"而挂起;另一个线程使"条件成立"(给出条件成立信号)。为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起。


条件变量类型为 pthread_cond_t

相关库函数简介

[cpp]  view plain  copy
  1. #include<pthread.h>  
  2. int pthread_cond_destroy(pthread_cond_t *cond);//条件变量的资源释放  
  3. int pthread_cond_init(pthread_cond_t *cond,const pthread_condattr_t *attr);//条件变量的初始化  
  4.    

[cpp]  view plain  copy
  1. #include<pthread.h>  
  2. int pthread_cond_timedwait(pthread_cond_t *restrict cond,pthread_mutex_t *mutex,  
  3. const struct timespec *abstime);  
  4. int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);  
  5. //等待某个条件是否成立。对于timewait()函数除了等待以外,可以设置一个时长。   
  6. int pthread_cond_signal(pthread_cond_t *cond);//种情况是只有一个线程收到后执行动作。  
  7. //活动线程只需要唤醒第一个正在睡眠的线程。假设您只对队列添加了一个工作作业。那么只需要唤醒一个工作程序线程(再唤醒其它线程是不礼貌的!)  
  8. int pthread_cond_broadcast(pthread_cond_t *cond);//通过广播的形式发给子线程消息,子线程竞争执行。  

无论哪种等待方式,都必须和互斥锁结合,以防止多个线程同时请求pthread_cond_wait()(或pthread_cond_timedwait())的竞争条件,且在调用pthread_cond_wait()前必须由本线程加锁(pthread_mutex_lock()),而在更新条件等待队列以前,mutex保持锁定状态,并在线程挂起进入等待前解锁。在条件满足从而离开pthread_cond_wait()之前,mutex将被重新加锁,以与进入pthread_cond_wait()前的加锁动作对应。

[cpp]  view plain  copy
  1. #include <stdlib.h>  
  2. #include <pthread.h>  
  3. #include <stdio.h>  
  4. #include <unistd.h>  
  5.   
  6. struct msg {  
  7.     struct msg *next;  
  8.     int num;  
  9. };  
  10.   
  11. struct msg *head;  
  12. /* 条件变量 */  
  13. pthread_cond_t has_product = PTHREAD_COND_INITIALIZER;  
  14. pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;  
  15. void *consumer(void *p)  
  16. {  
  17.     struct msg *mp;  
  18.     while(1)  
  19.     {  
  20.         pthread_mutex_lock(&lock);  
  21.         /* pthread_cond_wait(&has_product, &lock); 
  22.          * 1.阻塞等待has_product被唤醒, 
  23.          * 2.释放互斥锁, pthread_mutex_unlock(&lock) 
  24.          * 3.当被唤醒时,解除阻塞,并且重新去申请获得互斥锁 pthread_mutex_lock(&lock) 
  25.          */  
  26.         while (head == NULL)  
  27.             pthread_cond_wait(&has_product, &lock);//等待  
  28.   
  29.         mp = head;  
  30.         head = mp->next;  
  31.         pthread_mutex_unlock(&lock);  
  32.         printf("Consume %d\n", mp->num);  
  33.         free(mp);  
  34.         sleep(rand() % 5);  
  35.     }  
  36. }  
  37.   
  38. void *producer(void *p)  
  39. {  
  40.     struct msg *mp;  
  41.     while(1)  
  42.     {  
  43.         mp =(struct msg *)malloc(sizeof(struct msg));  
  44.         mp->num = rand() % 1000 + 1;  
  45.         printf("Produce %d\n", mp->num);  
  46.         pthread_mutex_lock(&lock);  
  47.         mp->next = head;  
  48.         head = mp;  
  49.         pthread_mutex_unlock(&lock);  
  50.         /* pthread_cond_broadcast(&has_product) 唤醒等待队列上的所有线程*/  
  51.         //发送信号,告诉消费者有产品了  
  52.         pthread_cond_signal(&has_product);  
  53.         sleep(rand() % 5);  
  54.     }  
  55. }  
  56.   
  57. int main(int argc, char *argv[])  
  58. {  
  59.     pthread_t pid, cid;  
  60.     srand(time(NULL));  
  61.     pthread_create(&pid, NULL, producer, NULL);  
  62.     pthread_create(&cid, NULL, consumer, NULL);  
  63.     pthread_join(pid, NULL);  
  64.     pthread_join(cid, NULL);  
  65.     return 0;  
  66. }  

猜你喜欢

转载自blog.csdn.net/u011124985/article/details/80065984