关于Condition Variable的一些思考

可能大家都使用过condition variable(之后称cv)

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

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

ok!让我们来从零开始。

condition variable(之后统一叫做cv)的初衷是为了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(); //3lock;
signaled = true; //4unlock;

这样我们把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(); //2unlock;thread 2:lock;cv.signal(); //3
signaled = true; //4unlock;

这样就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上,保证对称性。

时间: 2024-10-26 16:46:05

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

Linux Condition Variable条件变量避免锁冲突

条件变量Condition Variable的一般用法: 唤醒用法: 1 struct { 2 pthread_mutex_t mutex; 3 pthread_cond_t cond; 4 //whatever variables maintain the condition 5 ) var = { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, ... };//声明结构体并初始化 6 7 pthread_mutex_lock(&var

mutex&condition variable 黄金搭档之 多消费者多生产者

Condition Variable都会搭配一个Mutex来用.我们知道Mutex的普通意义上是维持一个互斥变量,从而保证一个或一组操作的原子性.同样,简单的说Mutex加在Condition Variable上也是为了保证它的原子性了.Condition Variable,有条件的唤醒机制.最经典不过的就是生产--消息者模型了.但有一个细节,消费者需要有"产品"才能继续它的消费行为,因此当消费者发现"产品"被消费完了?它该怎么办?没错,普通情况下它就会进入等待挂起

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

本文分析的是llvm libc++的实现:http://libcxx.llvm.org/ C++11中的各种mutex, lock对象,实际上都是对posix的mutex,condition的封装.不过里面也有很多细节值得学习. std::mutex 先来看下std::mutex: 包增了一个pthread_mutex_t __m_,很简单,每个函数该干嘛就干嘛. class mutex { pthread_mutex_t __m_; public: mutex() _NOEXCEPT {__m

C++11中std condition variable的使用

<condition_variable>是C++标准程序库中的一个头文件,定义了C++11标准中的一些用于并发编程时表示条件变量的类与方法等. 条件变量是并发程序设计中的一种控制结构.多个线程访问一个共享资源(或称临界区)时,不但需要用互斥锁实现独享访问以避免并发错误(称为竞争危害),在获得互斥锁进入临界区后还需要检验特定条件是否成立: (1).如果不满足该条件,拥有互斥锁的线程应该释放该互斥锁,把自身阻塞(block)并挂到(suspend)条件变量的线程队列中 (2).如果满足该条件,拥有

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

8.6 条件变量(Condition Variables)——可利用临界区或SRWLock锁来实现 8.6.1 条件变量的使用 (1)条件变量机制就是为了简化 “生产者-消费者”问题而设计的一种线程同步机制.其目的让线程以原子方式释放锁并将自己阻塞,直到某一个条件成立为止.如读者线程当没有数据可读取时,则应释放锁并等待,直到写者线程产生了新的数据.同理,当写者把数据结构写满时,那么写者应该释放SRWLock并等待,直到读者把数据结构清空. (2)等待函数:SleepConditionVariab

条件变量(Condition Variable)详解

转载于:http://blog.csdn.net/erickhuang1989/article/details/8754357 条件变量(Condtion Variable)是在多线程程序中用来实现"等待->唤醒"逻辑常用的方法.举个简单的例子,应用程序A中包含两个线程t1和t2.t1需要在bool变量test_cond为true时才能继续执行,而test_cond的值是由t2来改变的,这种情况下,如何来写程序呢?可供选择的方案有两种: 第一种是t1定时的去轮询变量test_co

Windows线程同步【5】条件变量(Condition Variable)

一.引言 假设有一个任务,由我和张三共同完成.张三把寄来的文稿初步审阅后放入一个队列,我负责将这个队列中的文稿进行审批,决定刊登与否.张三审阅一份文稿需要15分钟,我处理一个文稿需要2分钟. 如果将张三和我看作两个线程,那么我们共享一个队列的数据.按照一般的多线程思路,他每隔一段时间往队列中放入数据,我每隔一段时间检查一下队列中是否有数据,若有,则处理之. 若我们按照上面的方式工作,则大部分的时间,我只是在干等着,所以,这是一种比较低效的方式. 但换一种方式之后,情况就好很多了.他每把一个文稿放

条件变量的陷阱与思考

一.前言 在多线程编程中,互斥锁与条件变量恐怕是最常用也是最实用的线程同步原语. 关于条件变量一共也就pthread_cond_init.pthread_cond_destroy.pthread_cond_wait.pthread_cond_timedwait.pthread_cond_signal.pthread_cond_broadcast这么几个函数,但是在实际使用中却是很容易用错,后文将来分析几种常见使用情况的正确性. 二.分析 下面是一个辅助基类.便于减少篇幅(由于简单起见,后文中的所

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

使用Condition Variables实现一个线程安全队列 多线程代码需要面对的一个问题和是如何把数据从一个县城传到另一个县城. 举个栗子,一个常见的是把串行算法并行化方法是,把他们分成块并且做成一个管道.管道中任意一块都可以单独在一个线程里运行.每个阶段完成后添加数据到输入队列给下个阶段. Basic Thread Safety with a Mutex 使用mutex实现简单的线程安全 最简单的办法是封装一个非线程安全的队列,使用mutex保护它(实例使用boost中的方法和类型,需要1