【C语言】【unix c】条件变量线程同步

短命女 2022-06-07 08:54 382阅读 0赞
  1. 什么是条件变量?
  2. 线程a等待某个条件成立,条件成立,线程a才继续向下执行。线程b的执行使条件成立,条件成立之后唤醒线程a,以继续执行。这个条件就是条件变量
  3. pthread_cond_t 就是条件变量类型
  4. 对类型的封装如下:
  5. #include <pthread.h>
  6. pthread_cond_t cond = PTHREAD_COND_INITIALIZER; //条件变量的静态初始化,定义变量可以用
  7. int pthread_cond_init(pthread_cond_t *cond,pthread_condattr_t *cond_attr);
  8. 功能:初始化一个条件变量
  9. 参数:
  10. cond:指定要初始化的条件变量(指向结构pthread_cond_t的指针)
  11. cond_attrNULL 默认的(用于设置条件变量是进程内还是进程间的)
  12. 返回值:0 成功
  13. 0 错误
  14. int pthread_cond_signal(pthread_cond_t *cond);
  15. 功能:启动在等待条件变量变为真的一个线程,每次最多可以给一个线程发送
  16. 参数:
  17. cond:指定条件变量
  18. 返回值:0 成功
  19. 0 错误
  20. int pthread_cond_broadcast(pthread_cond_t *cond);
  21. 功能:启动所有的等待条件变量为真的线程
  22. 参数:
  23. cond:指定条件变量
  24. 返回值:0 成功
  25. 0 错误
  26. int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); //等待期间不会占用cpu,先解锁,然后进入睡眠状态,等待接受信号
  27. 功能:等待条件变量为真(无条件等待)
  28. 参数:
  29. cond:指定等待的条件变量
  30. mutex:等待之前需要解开的锁
  31. 返回值:0 成功
  32. 0 错误
  33. int pthread_cond_timedwait(pthread_cond_t *cond,pthread_mutex_t *mutex, const struct timespec *abstime); //超时等待
  34. 功能:超时等待,超时返回错误(计时等待)
  35. 参数:
  36. cond:指定等待的条件变量
  37. mutex:等待之前需要解开的锁
  38. abstime:指定等待的时间
  39. 返回值:0 成功
  40. 0 错误
  41. int pthread_cond_destroy(pthread_cond_t *cond);
  42. 功能:销毁一个条件变量
  43. 参数:
  44. cound:指定要销毁的条件变量
  45. 返回值:0 成功
  46. 0 错误
  47. 操作步骤:
  48. 1、解开mutex
  49. 2、让线程等待条件变量为真
  50. 3、条件变量为真时加锁
  51. 生产者和消费者(读者和写者)
  52. 链表实现:生产者生产出来对象,放到链表头部,消费者从链表的头部取出消费
  53. 第一个思考:两个线程如何同步访问链表的头部
  54. 第二个思考:如果链表为空,消费者等待生产者生产对象
  55. 第三个思考:生产者线程生产出对象需要通知消费者
  56. 代码见 cond.c
  57. #include <stdio.h>
  58. #include <pthread.h>
  59. #include <stdlib.h>
  60. #include <time.h>
  61. typedef struct node{
  62. int num;
  63. struct node *next;
  64. }node_t;
  65. typedef node_t *list_t;
  66. list_t head=NULL;
  67. pthread_mutex_t mutex=\
  68. PTHREAD_MUTEX_INITIALIZER;
  69. pthread_cond_t cond=\
  70. PTHREAD_COND_INITIALIZER;
  71. //消费者线程
  72. void *consume(void *arg){
  73. node_t *tmp;
  74. while(1){
  75. //加锁
  76. pthread_mutex_lock(&mutex);//对临界变量加锁
  77. if(head==NULL)//如果头部指向空,等待
  78. pthread_cond_wait(&cond,&mutex);
  79. tmp=head;//将要删除的节点赋值给中间值,然后头指针指向下一个
  80. head=head->next;//
  81. //解锁
  82. pthread_mutex_unlock(&mutex);
  83. //消费tmp节点
  84. printf("consum:%d\n",tmp->num);
  85. free(tmp);
  86. tmp=NULL;
  87. sleep(rand()%5);
  88. }
  89. }
  90. //生产者线程
  91. void *product(void *arg){
  92. //函数的格式void *(*start_routine) (void *),返回值是指针,参数也是
  93. node_t *n;
  94. while(1){
  95. //生产一个新的节点
  96. n=(node_t *)malloc(sizeof(node_t));
  97. n->num=rand()%1000+1;
  98. printf("p:%d\n",n->num);
  99. //加锁
  100. pthread_mutex_lock(&mutex);
  101. //将新节点放入到链表的头部
  102. n->next=head;
  103. head=n;
  104. //解锁
  105. pthread_mutex_unlock(&mutex);
  106. //通知消费者
  107. pthread_cond_signal(&cond);
  108. sleep(rand()%5);
  109. }
  110. }
  111. int main(void){
  112. pthread_t pid,cid;
  113. //设置随机数的种子
  114. srand(time(NULL));
  115. //创建两个线程,用于生产者和消费者
  116. pthread_create(&pid,NULL,product,NULL);//创建线程后即执行该线程
  117. pthread_create(&cid,NULL,consume,NULL);//参数含义是(存放ID的缓存区,NULL缺省属性,线程的执行函数,函数的唯一参数)
  118. //等待线程的汇合
  119. pthread_join(pid,NULL);
  120. pthread_join(cid,NULL);
  121. //销毁mutex锁
  122. pthread_mutex_destroy(&mutex);
  123. pthread_cond_destroy(&cond);
  124. return 0;
  125. }
  126. tarena@ubuntu:~/day/day37$ gcc cond.c -lpthread
  127. tarena@ubuntu:~/day/day37$ a.out
  128. p:637
  129. consum:637
  130. p:741
  131. consum:741
  132. p:243
  133. consum:243
  134. p:651
  135. consum:651
  136. p:252
  137. consum:252
  138. p:244
  139. p:612
  140. p:954
  141. p:627
  142. p:564
  143. consum:564
  144. p:941
  145. consum:941
  146. p:347
  147. consum:347
  148. p:28
  149. consum:28
  150. p:60
  151. p:174
  152. consum:174
  153. p:824
  154. p:359
  155. consum:359
  156. consum:824
  157. p:671
  158. p:8
  159. p:164
  160. ^C
  161. 分析:链表会将之前没有出来的先压在下面,直到前面的输出完才会将他们输出来

发表评论

表情:
评论列表 (有 0 条评论,382人围观)

还没有评论,来说两句吧...

相关阅读