什么是条件变量(condition variables)

引用APUE中的一句话:

Condition variables are another synchronization mechanism available to threads.
These synchronization objects provide a place for threads to rendezvous. When used with mutexes, condition variables allow threads to wait in a race-free way for arbitrary conditions to occur.

条件变量是线程的另外一种同步机制,这些同步对象为线程提供了会合的场所,理解起来就是两个(或者多个)线程需要碰头(或者说进行交互-一个线程给另外的一个或者多个线程发送消息),我们指定在条件变量这个地方发生,一个线程用于修改这个变量使其满足其它线程继续往下执行的条件,其它线程则接收条件已经发生改变的信号。

条件变量同锁一起使用使得线程可以以一种无竞争的方式等待任意条件的发生。所谓无竞争就是,条件改变这个信号会发送到所有等待这个信号的线程。而不是说一个线程接受到这个消息而其它线程就接收不到了。

一个例子

具体的函数介绍就不说了,详细参考APUE,下面通过一个例子来详细说一下正确使用条件变量的方法。下例实现了生产者和消费者模型,生产者向队列中插入数据,消费者则在生产者发出队列准备好(有数据了)后接收消息,然后取出数据进行处理。实现的关键点在以下几个方面:

  • 生产者和消费者都对条件变量的使用加了锁
  • 消费者调用pthread_cond_wait,等待队列是否准备好的信息,注意参数有两个,一个是pthread_cond_t,另外一个是pthread_mutex_t.
#include <pthread.h>
struct msg {struct msg *m_next;
/* ... more stuff here ... */
};
struct msg *workq;
pthread_cond_t qready = PTHREAD_COND_INITIALIZER;
pthread_mutex_t qlock = PTHREAD_MUTEX_INITIALIZER;void process_msg(void)
{struct msg *mp;for (;;) {pthread_mutex_lock(&qlock);while (workq == NULL)pthread_cond_wait(&qready, &qlock);mp = workq;workq = mp->m_next;pthread_mutex_unlock(&qlock);/* now process the message mp */}
}void enqueue_msg(struct msg *mp)
{pthread_mutex_lock(&qlock);mp->m_next = workq;workq = mp;pthread_mutex_unlock(&qlock);pthread_cond_signal(&qready);
}

关于上面例子的几个疑问

为什么pthread_cond_wait需要加锁??

pthread_cond_wait中的mutex用于保护条件变量,调用这个函数进行等待条件的发生时,mutex会被自动释放,以供其它线程(生产者)改变条件,pthread_cond_wait中的两个步骤必须是原子性的(atomically,万恶的APUE中文版把这个单词翻译成了『自动』,误人子弟啊),也就是说必须把两个步骤捆绑到一起:

  • 把调用线程放到条件等待队列上
  • 释放mutex

不然呢,如果不是原子性的,上面的两个步骤中间就可能插入其它操作。比如,如果先释放mutex,这时候生产者线程向队列中添加数据,然后signal,之后消费者线程才去『把调用线程放到等待队列上』,signal信号就这样被丢失了。

如果先把调用线程放到条件等待队列上,这时候另外一个线程发送了pthread_cond_signal(我们知道这个函数的调用是不需要mutex的),然后调用线程立即获取mutex,两次获取mutex会产生deadlock.

在生产者线程中修改条件时为什么要加mutex??

如果不这么做信号可能会丢失,看下面的例子:

Thead A                             Thread Bpthread_mutex_lock(&qlock);
while (workq == NULL)mp->m_next = workq;workq = mp;pthread_cond_signal(&cond);pthread_cond_wait(&qready, &qlock);

在while判断之后向队列中插入数据,虽然已经有数据了,但线程A还是调用了pthread_cond_wait等待下一个信号到来。。

消费者线程中判断条件为什么要放在while中??

while (workq == NULL)pthread_cond_wait(&qready, &qlock);
mp = workq;

我们把while换成if可不可以呢?

if (workq == NULL)pthread_cond_wait(&qready, &qlock);
mp = workq;

答案是不可以,一个生产者可能对应着多个消费者,生产者向队列中插入一条数据之后发出signal,然后各个消费者线程的pthread_cond_wait获取mutex后返回,当然,这里只有一个线程获取到了mutex,然后进行处理,其它线程会pending在这里,处理线程处理完毕之后释放mutex,刚才等待的线程中有一个获取mutex,如果这里用if,就会在当前队列为空的状态下继续往下处理,这显然是不合理的。

signal到底是放在unlock之前还是之后??

void enqueue_msg(struct msg *mp)
{pthread_mutex_lock(&qlock);mp->m_next = workq;workq = mp;pthread_mutex_unlock(&qlock);pthread_cond_signal(&qready);
}

如果先unlock,再signal,如果这时候有一个消费者线程恰好获取mutex,然后进入条件判断,这里就会判断成功,从而跳过pthread_cond_wait,下面的signal就会不起作用;另外一种情况,一个优先级更低的不需要条件判断的线程正好也需要这个mutex,这时候就会转去执行这个优先级低的线程,就违背了设计的初衷。

void enqueue_msg(struct msg *mp)
{pthread_mutex_lock(&qlock);mp->m_next = workq;workq = mp;pthread_cond_signal(&qready);pthread_mutex_unlock(&qlock);
}

如果把signal放在unlock之前,消费者线程会被唤醒,获取mutex发现获取不到,就又去sleep了。浪费了资源.但是在LinuxThreads或者NPTL里面,就不会有这个问题,因为在Linux 线程中,有两个队列,分别是cond_wait队列和mutex_lock队列, cond_signal只是让线程从cond_wait队列移到mutex_lock队列,而不用返回到用户空间,不会有性能的损耗。
所以在Linux中推荐使用这种模式。

深入解析条件变量(condition variables)相关推荐

  1. 对条件变量(condition variable)的讨论

    作者:王东 1.1       什么是条件变量和条件等待? 简单的说: 条件变量(condition variable)是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待某个 ...

  2. python 线程超时设置_python 条件变量Condition(36)

    文章首发微信公众号,微信搜索:猿说python 对于线程与线程之间的交互我们在前面的文章已经介绍了 python 互斥锁Lock / python事件Event , 今天继续介绍一种线程交互方式 – ...

  3. Python 线程条件变量 Condition - Python零基础入门教程

    目录 一.Python 线程条件变量 Condition 函数 二.Python 线程条件变量 Condition 原理 三.Python 线程条件变量 Condition 使用 四.Python 线 ...

  4. 条件变量(condition variable)详解

    原理: 假设我们需要解决这样一个问题:一个列表记录需要处理的任务.一个线程往此列表添加任务,一个线程processTask处理此列表中的任务.这个问题的一个关键点在于processTask怎么判断任务 ...

  5. c++11 多线程编程(六)------条件变量(Condition Variable)

    互斥锁std::mutex是一种最常见的线程间同步的手段,但是在有些情况下不太高效. 假设想实现一个简单的消费者生产者模型,一个线程往队列中放入数据,一个线程往队列中取数据,取数据前需要判断一下队列中 ...

  6. 用C++ 封装linux下的互斥锁MutexLock和条件变量Condition

    /*封装互斥锁的时候,要用到的方法,20200605*/ //问题一:MutexLock和Condition是否要设计成单例模式? // 单例模式只能通过该类创建出一个对象,这意味着只能创建一把锁,如 ...

  7. Linux操作系统下的多线程编程详细解析----条件变量pthread_cond_t那些事儿

    推荐两个博文: http://www.cnblogs.com/Creator/archive/2012/04/18/2455584.html http://blog.csdn.net/sunboy_2 ...

  8. Linux操作系统下的多线程编程详细解析----条件变量

    条件变量通过允许线程阻塞和等待另一个线程发送信号的方法,弥补了互斥锁(Mutex)的不足. 1.初始化条件变量pthread_cond_init #include <pthread.h> ...

  9. c++11多线程编程同步——使用条件变量condition variable

    简述 在多线程编程中,当多个线程之间需要进行某些同步机制时,如某个线程的执行需要另一个线程完成后才能进行,可以使用条件变量. c++11提供的 condition_variable 类是一个同步原语, ...

  10. Linux下多线程编程互斥锁和条件变量的简单使用

    Linux下的多线程遵循POSIX线程接口,称为pthread.编写Linux下的多线程程序,需要使用头文件pthread.h,链接时需要使用库libpthread.a.线程是进程的一个实体,是CPU ...

最新文章

  1. java 消息队列_java消息队列
  2. python中面向对象空间时间_python基础学习Day15 面向对象、类名称空间、对象名称空间 (2)...
  3. 从Bayes角度理解Deep learning
  4. php 读写excel 网络错误,谁用过PHPExcel,导出的文件报“无法读取的内容”错误
  5. Python源码深度解析—对象的创建
  6. 宏基ACER Aspire R3600 REVO离子平台
  7. 基于STM32构建EtherCAT主站(SOEM方案)5
  8. 学术论文海报模板_推荐 | 绘制学术论文中的图表一般有哪些专业的软件?
  9. 锐捷交换机配置snmp版本_原创整理:锐捷S3550系列交换机基本配置命令(一)
  10. python如何设计系统界面教程_python图形化界面设计tkinter!python用户界面设计教程...
  11. 如何取得销售订单中订单货币和本位币之间的汇率 (exchange rate)
  12. 多个excel表格数据汇总如何完成
  13. window.print()+layer.open()——实现打印A4纸张内容的功能——功能实现
  14. /home/ljx/miniconda3/compiler_compat/ld: cannot find crtbeginS.o: 没有那个文件或目录
  15. [04]Web前端进阶—JS伪数组
  16. 软文网络推广的几个写作技巧
  17. ehviewer怎么搜索关键字_ehviewer
  18. Android创建Excel表格
  19. 远程桌面连接不上,三种方法教你重启服务器
  20. python dataframe去掉索引_python中pandas.DataFrame(创建、索引、增添与删除)的简单操作方法介绍...

热门文章

  1. python学习之老男孩python全栈第九期_day022作业
  2. 阿里财报揭秘:阿里巴巴最忙的人这一年都干了啥
  3. 使用nginx反向代理解决前端跨域问题
  4. Hadoop - 任务调度系统比较
  5. Super超图,GIS软件
  6. 什么样的文章更容易被编辑推荐?
  7. 50. 模型层 --- dao 层(2)
  8. 12. Element attributes 属性
  9. 监控linux内存,系统运维|用 Bash 脚本监控 Linux 上的内存使用情况
  10. mysql .net2.0_MySQL和.Net2.0合营哄骗