条件变量

  • 当一个线程互斥地访问某个变量时,它可能发现在其它线程改变状态之前,它什么也做不了
  • 例如一个线程访问队列时,发现队列为空,它只能等待,只到其它线程将一个节点添加到队列中。这种情况就需要用到条件变量

条件变量和互斥锁为什么要配合使用?

  1. 条件本身就是公共资源,多个线程同时方式时,必须使用互斥锁在临界区内对条件进行保护。
  2. 条件变量的作用是在等待某个条件达成时自身要进行睡眠或阻塞,避免忙等待带来的不必要消耗;当被唤醒时,会重新尝试加锁,如果锁成功,才进行之后的流程;否则解锁,继续阻塞

条件变量函数

pthread_cond_init

  1. 功能:
  2. initialize condition variables
  3. 原型:
  4. int pthread_cond_init(pthread_cond_t *restrict cond,
  5. const pthread_condattr_t *restrict attr);
  6. pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
  7. 参数:
  8. cond 指向结构pthread_cond_t的指针
  9. attr 条件变量的属性结构的指针
  10. 返回值:
  11. 成功 0
  12. 失败 返回错误码

pthread_cond_destroy

  1. 功能:
  2. destroy condition variables
  3. 原型:
  4. int pthread_cond_destroy(pthread_cond_t *cond);
  5. 参数:
  6. cond 指向结构pthread_cond_t的指针
  7. 返回值:
  8. 成功 0
  9. 失败 返回错误码

pthread_cond_wait

  1. 功能:
  2. wait on a condition
  3. 原型:
  4. int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
  5. 参数:
  6. cond 指向结构pthread_cond_t的指针
  7. mutex : 互斥锁
  8. 返回值:
  9. 成功 0
  10. 失败 返回错误码

pthread_cond_signal

  1. 功能:
  2. signal a condition
  3. 原型:
  4. int pthread_cond_signal(pthread_cond_t *cond);
  5. 参数:
  6. cond 指向结构pthread_cond_t的指针
  7. 返回值:
  8. 成功 0
  9. 失败 返回错误码

pthread_cond_broadcast

  1. 功能:
  2. signal a condition
  3. 原型:
  4. broadcast a condition
  5. 参数:
  6. cond 指向结构pthread_cond_t的指针
  7. 返回值:
  8. 成功 0
  9. 失败 返回错误码

条件变量使用规范

等待条件代码

  1. pthread_mutex_lock(&mutex);
  2. while(条件为假)
  3. pthread_cond_wait(cond, mutex);
  4. 修改条件
  5. pthread_mutex_unlock(&mutex);

给条件发送信号代码

  1. pthread_mutex_lock(&mutex);
  2. 设置条件为真
  3. pthread_cond_signal(cond);
  4. pthread_mutex_unlock(&mutex);

使用条件变量解决生产者、消费者问题

  1. #include <unistd.h>
  2. #include <sys/types.h>
  3. #include <pthread.h>
  4. #include <stdlib.h>
  5. #include <stdio.h>
  6. #include <errno.h>
  7. #include <string.h>
  8. #include <semaphore.h>
  9. #define ERR_EXIT(m) \
  10. do \
  11. { \
  12. perror(m); \
  13. exit(EXIT_FAILURE); \
  14. } while (0)
  15. #define CONSUMERS_COUNT 2 //消费者线程的个数
  16. #define PRODUCERS_COUNT 1 //生产者线程的个数
  17. int nready = 0;
  18. pthread_cond_t g_cond;
  19. pthread_mutex_t g_mutex;
  20. pthread_t g_thread[CONSUMERS_COUNT + PRODUCERS_COUNT]; //总线程数
  21. void *consume(void *arg)
  22. {
  23. int num = (int)arg;
  24. while (1)
  25. {
  26. pthread_mutex_lock(&g_mutex);
  27. while(nready == 0)
  28. {
  29. printf("%d wait a condition...\n", num);
  30. pthread_cond_wait(&g_cond, &g_mutex);
  31. }
  32. printf("%d end wait...\n", num);
  33. printf("%d begin consume product...\n",num);
  34. --nready;
  35. printf("%d end consume product...\n",num);
  36. pthread_mutex_unlock(&g_mutex);
  37. sleep(1);
  38. }
  39. return NULL;
  40. }
  41. void *produce(void *arg)
  42. {
  43. int num = (int)arg;
  44. while (1)
  45. {
  46. pthread_mutex_lock(&g_mutex);
  47. printf("%d begin produce product...\n", num);
  48. ++nready;
  49. printf("%d end produce product...\n", num);
  50. pthread_cond_signal(&g_cond);
  51. printf("%d singal ...\n",num);
  52. pthread_mutex_unlock(&g_mutex);
  53. sleep(1);
  54. }
  55. return NULL;
  56. }
  57. int main()
  58. {
  59. int i;
  60. pthread_cond_init(&g_cond, NULL);
  61. pthread_mutex_init(&g_mutex, NULL);
  62. for (i = 0; i < CONSUMERS_COUNT; ++i)
  63. {
  64. pthread_create(&g_thread[i], NULL, consume, (void *)i);
  65. }
  66. sleep(1);
  67. for (i = 0; i < PRODUCERS_COUNT; ++i)
  68. {
  69. pthread_create(&g_thread[CONSUMERS_COUNT + i], NULL, produce, (void *)i);
  70. }
  71. for (i = 0; i < CONSUMERS_COUNT + PRODUCERS_COUNT; ++i)
  72. {
  73. pthread_join(g_thread[i], NULL);
  74. }
  75. pthread_cond_destroy(&g_cond);
  76. pthread_mutex_destroy(&g_mutex);
  77. return 0;
  78. }

pthread_cond_wait

  1. 对mutex进行解锁
  2. 等待条件,直到有线程向它发起通知
  3. 重新对mutex进行加锁操作

pthread_cond_signal

向等待的条件的线程发起通知,如果没有任何一个处于等待条件的状态,这个通知将被忽略

为什么要用while

  1. pthread_cond_wait会自动重启,就像这个信号没有发生过一样
  2. pthread_cond_wait可能会被虚假的唤醒,当被虚假唤醒后,需要重新判断条件

第四十章 POSIX条件变量的更多相关文章

  1. Linux多线程实践(8) --Posix条件变量解决生产者消费者问题

    Posix条件变量 int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr); int pthread_co ...

  2. posix 条件变量与互斥锁 示例生产者--消费者问题

    一.posix 条件变量 一种线程间同步的情形:线程A需要等某个条件成立才能继续往下执行,现在这个条件不成立,线程A就阻塞等待,而线程B在执行过程中使这个条件成立了,就唤醒线程A继续执行. 在pthr ...

  3. Linux多线程实践(六)使用Posix条件变量解决生产者消费者问题

    前面的一片文章我们已经讲过使用信号量解决生产者消费者问题.那么什么情况下我们须要引入条件变量呢? 这里借用  http://www.cnblogs.com/ngnetboy/p/3521547.htm ...

  4. linux网络编程之posix条件变量

    今天来学习posix的最后一个相关知识----条件变量,言归正传. 下面用一个图来进一步描述条件变量的作用: 为什么呢? 这实际上可以解决生产者与消费者问题,而且对于缓冲区是无界的是一种比较理解的解决 ...

  5. linux网络编程-posix条件变量(40)

    举一个列子来说明条件变量: 假设有两个线程同时访问全局变量n,初始化值是0, 一个线程进入临界区,进行互斥操作,线程当n大于0的时候才执行下面的操作,如果n不大于0,该线程就一直等待. 另外一个线程也 ...

  6. POSIX条件变量

    条件变量: 当一个线程互斥的访问某个变量时,它可能发现其他线程改变状态之前,它什么都做不了例如:一个线程访问队列时,发现队列为空,它只能等待,直到其他线程将一个节点添加到队列中,这种情况就需要使用条件 ...

  7. Linux互斥锁、条件变量和信号量

    Linux互斥锁.条件变量和信号量  来自http://kongweile.iteye.com/blog/1155490 http://www.cnblogs.com/qingxia/archive/ ...

  8. 进程间通信机制(管道、信号、共享内存/信号量/消息队列)、线程间通信机制(互斥锁、条件变量、posix匿名信号量)

    注:本分类下文章大多整理自<深入分析linux内核源代码>一书,另有参考其他一些资料如<linux内核完全剖析>.<linux c 编程一站式学习>等,只是为了更好 ...

  9. 并发编程(一): POSIX 使用互斥量和条件变量实现生产者/消费者问题

    boost的mutex,condition_variable非常好用.但是在Linux上,boost实际上做的是对pthread_mutex_t和pthread_cond_t的一系列的封装.因此通过对 ...

随机推荐

  1. python 写入txt的新方法

    最新发现有新方法可以对txt等进行操作,比较有意思,之前没见过,故记录下 传统方法 with open(ur'D:\Desktop\a123.txt', 'a') as f: #以写的方式打开 f.w ...

  2. Ansible Roles角色

    Roles小技巧: 1.创建roles目录结构,手动或使用ansible-galaxy init test roles 2.编写roles的功能,也就是tasks. nginx rsyncd memc ...

  3. mapper插入时显示中文

    可能是jdbc url需要加characterEncoding=utf-8,例 jdbc:mysql://localhost:3306/smbms?characterEncoding=utf8

  4. Linux学习资料网站汇总链接(持续更新ing)

    排名不分先后. 学海无涯苦作舟. 博客: 1.slmba:LINUX博客原创大牛 2.edsionte's TechBlog:Linuxer (他的友情链接中还有一堆Linuxer,被公司屏蔽进不去. ...

  5. python编程基础之十一

    循环语句:周而复始,在满足某个条件下,重复做相同或类型的事情, 循环语句三要素:循环条件 + 循环体 + 循环条件改变while 条件 : 循环体 循环条件改变... while 条件 : 循环体 循 ...

  6. [洛谷] 通往奥格瑞玛的道路 [Vijos]

    题目背景 在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量 有一天他醒来后发现自己居然到了联盟的主城暴风城 在被众多联盟的士兵攻击后,他决定逃回自己的家乡奥格瑞玛 题目描述 在艾泽拉斯, ...

  7. Java线程状态和关闭线程的正确姿势

    1.线程状态及切换 Java中的线程有六种状态,使用线程Thread内的枚举类来实现,如下,我对每个状态都进行了一定的解释. public enum State { /** 表示一个线程还没启用(即未 ...

  8. Centos7安装及配置DHCP服务

    DHCP服务概述: 名称:DHCP  - Dynamic Host Configuration Protocol  动态主机配置协议. 功能:DHCP(Dynamic Host Configurati ...

  9. MySQL学习(三)MySQL锁与事务

    本章我们着重讨论MySQL锁机制的特点,常见的锁问题,以及解决MySQL锁问题的一些方法或建议. 一.MySQL锁概述 相对其他数据库而言,MySQL的锁机制比较简单,其最显著的特点是不同的存储引擎支 ...

  10. Linux命令行与shell脚本

    一.Linux简介 1.linux系统内部结构 划分为以下四部分:linux内核.GNU工具组件.图形化桌面环境.应用软件. 2.Linux系统的核心——内核 内核基本负责以下四项主要功能:系统内存管 ...