可能大家都使用过condition variable(之后称cv),一些博客也对cv做了介绍,但是有的说的不完全正确,甚至有误导使用者的倾向,其实最合理的使用方式是查阅文档,

如果你英语还ok的话,http://en.cppreference.com/w/cpp/thread/condition_variable 读一遍即可 完全没有必要看我写的这些砖块,但是我的blog可能思路上更贴近初学者,可以借鉴一下。

背景不过多做介绍,使用condition variable的时候都要配合mutex使用,那么mutex就是为了什么呢,为什么要用这个东西呢?

为什么要这样设计?mutex多余吗?他是用来保护什么数据呢?

ok!让我们来从零开始。

condition variable的初衷是为了wait某一个东东变成true或false,然后此线程继续进行。

按照此需求,大概的代码应该是这样:

//version 1.0
Thread 1:
cv.wait();
Thread 2:
cv.signal();

这样的话有一个很严重的问题,如果t2先执行,那么t1岂不是永远停在那里了!这样与我们最初的构想完全不符!

于是产生了下面的写法:

//version 2.0
bool signaled = false;
thread 1:
if(!signaled)
  cv.wait();
thread 2:
cv.signal();
signaled = true;

看上去不错吧!但是犯了一个很白痴的错误,bool并不是thread safe的,所以

//version 2.1
bool signaled = false;
thread 1:
lock;
if(!signaled) //1
  unlock;
  cv.wait(); //2
thread 2:
cv.signal(); //3
lock;
signaled = true; //4
unlock;

这样我们把signaled保护起来,保证thread safe了,会有什么问题吗?

当然有问题!如果执行顺序是这样的话,3-1-4-2 那么thread 1永远wait在那里了!

欸!为什么会这样呢!让我们从长计议!一开始为了保证signal是否发出,我们增加了一个标志位来判断是否信号已经发出,如果已经发出,那么cv不需要等待。接着,我们对thread safe进行了保证,然后现在又出现了执行顺序的问题!

仔 细思考一下,就会发现,其实导致问题的原因就在于需求的原子性并没有很好的用c++表达出来,你想想,thread 1的意思翻译成汉语就是“如果没有信号没有触发,那么我就等”,thread 2的意思很明显就是“触发!”,但是触发一句话到了c++语义中就变成了两个语句,多个指令,那么你很难满足我的需求,至少在不进行原子性语句约束的情况 下你无法满足我的需求。

所以 thread 1 这段代码就是一团糟!当进行wait操作之前,你能确定signaled为false吗?答案是否定的。

或者说thread 2 这段代码 当你signal之后,你的signaled马上变成true了吗? 答案也是否定的,你如果无法保证这两个语句的原子性,那么就无法达到需求。

所以我们继续修改:

//version 3.0
bool signaled = false;
thread 1:
lock;
if(!signaled) //1
  cv.wait(); //2
unlock;
thread 2:
lock;
cv.signal(); //3
signaled = true; //4
unlock;

这样就ok了!但是如果你听说过spurious wakeup(可以自行查阅一下),那么3.0依然是不够完善的,

最终的版本是:

//version 4.0
bool signaled = false;
thread 1:
lock;
while(!signaled) //1
  cv.wait(); //2
unlock;
thread 2:
lock;
cv.signal(); //3
signaled = true; //4
unlock;

然后我们回到最初的问题上去,为什么需要传入一个参数mutex,答案就很显然了,是为了让cv进行unlock操作的,当cv拿回线程的权杖的时候,再把mutex lock上,保证对称性。

关于Condition Variable的一些思考的更多相关文章

  1. C++关于Condition Variable

    #include <condition_variable> #include <mutex> #include <future> #include <iost ...

  2. 关于condition variable的理解

    <span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255) ...

  3. c++并发编程之条件变量(Condition Variable)

    条件变量(Condition Variable)的一般用法是:线程 A 等待某个条件并挂起,直到线程 B 设置了这个条件,并通知条件变量,然后线程 A 被唤醒.经典的「生产者-消费者」问题就可以用条件 ...

  4. C++11中的mutex, lock,condition variable实现分析

    本文分析的是llvm libc++的实现:http://libcxx.llvm.org/ C++11中的各种mutex, lock对象,实际上都是对posix的mutex,condition的封装.不 ...

  5. Condition Variable使用及其Thread Cancellation线程取消

    条件变量Condition Variable的一般用法: 唤醒用法: struct { pthread_mutex_t mutex; pthread_cond_t cond; //whatever v ...

  6. 第8章 用户模式下的线程同步(4)_条件变量(Condition Variable)

    8.6 条件变量(Condition Variables)——可利用临界区或SRWLock锁来实现 8.6.1 条件变量的使用 (1)条件变量机制就是为了简化 “生产者-消费者”问题而设计的一种线程同 ...

  7. [转] 条件变量(Condition Variable)详解

    http://www.wuzesheng.com/?p=1668 条件变量(Condtion Variable)是在多线程程序中用来实现“等待->唤醒”逻辑常用的方法.举个简单的例子,应用程序A ...

  8. 条件变量(Condition Variable)详解

    条件变量(Condtion Variable)是在多线程程序中用来实现“等待->唤醒”逻辑常用的方法.举个简单的例子,应用程序A中包含两个线程t1和t2.t1需要在bool变量test_cond ...

  9. 使用Condition Variables 实现一个线程安全队列

    使用Condition Variables实现一个线程安全队列 测试机: i7-4800MQ .7GHz, logical core, physical core, 8G memory, 256GB ...

随机推荐

  1. Linux下卸载ORACLE的多种方法(转)

    第一种# cd /u01/app/oracle/product/11.2.0/client_1/deinstall/ # ./deinstall# rm -rf /u01/app/oracle# rm ...

  2. 自动工作负载库(Automatic Workload Repository,AWR)

    自动工作负载库(Automatic Workload Repository,AWR)AWR的由来:    10g之前的oracle:用户的连接将产生会话,当前会话记录保存在v$session中:处于等 ...

  3. Net Configuration Assistant和Net Manager的区别

    1.Net Configuration Assistant和Net Manager在oracle的配置工具中,Net Configuration Assistant(网络配置助手)和Net Manag ...

  4. golang高级部分

    一.golang之OOP(orient object programming) 在函数声明时, 在其名字之前放上一个变量, 即是一个方法. 这个附加的参数会将该函数附加到这种类型上, 即相当于为这种类 ...

  5. JS(移动端)自己封装移动端一些常用方法

    /** * Created by Administrator on 2016/7/14. */ /*命名空间*/ window.lcf = {}; /*监听过渡结束的方法*/ lcf.transiti ...

  6. UVA 10410 Tree Reconstruction

    题意: 给定一个树的BFS和DFS,求这棵树. 分析: 拿dfs的序列,分成若干段,每一段相当一个子树,这样就可以利用bfs的序列去将dfs的序列分段,然后利用一个队列去存放每一段,不断求出子树即可. ...

  7. mongodb简单初级操作

    学习之余记录,仅供参考 mongodb启动: mongodb安装在D:\mongodb 目录下,启动时在该目录bin文件夹下打开命令行窗口 在启动数据库时,将datapath参数指向db目录   输入 ...

  8. 数据库基础(变量、运算符、if语句、while语句)

    数据库基础(变量.运算符.if语句.while语句)   变量: 定义变量:declare @变量名 数据类型 变量赋值:set @变量名 = 值 输出:print 变量或字符串 SQL语言也跟其他编 ...

  9. codevs1127

    学校里有一个水房,水房里一共装有m 个龙头可供同学们打开水,每个龙头每秒钟的供水量相等,均为1. 现在有n 名同学准备接水,他们的初始接水顺序已经确定.将这些同学按接水顺序从1到n 编号,i 号同学的 ...

  10. Mysql源码安装

    首先去http://dev.mysql.com/downloads/mysql/5.6.html 下载mysql的源代码,记住是source code,别下别的版本 1.安装依赖的包 yum -y i ...