首先我们看只有一个reader/一个writer的情形
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp>
#include <iostream>
int number;
boost::mutex m;
boost::condition not_full;
boost::condition not_empty;
void writer()
{
}
void reader()
{
}
void main()
{
}
运行之后程序一切如常,0-5的一些数字会打印出来。
但是当另外一个write加入战局的时候,情况变得有些微妙的不同,如果我们只是在main里面加入一个writer,其他部分保持不变的话,你会看到一些错误的数字出现:
void main()
{
}
究其原因是:在reader->notify_one之后并在socped_lock解锁之前,在not_full上等待的writer A被唤起,然后reader解锁,此时可能另外一个writer B先获得锁而直接增加了number。在writeB 解锁后, writerA获得锁,但此时not_full条件已经被破坏。所以一种做法是再次检查该条件,也就是这样:
while (number == 5) {
}
对于多write或多reader的情形也是一样都需要以一个while循环进行conditiond的复检:完整的代码如下
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp>
#include <iostream>
int number;
boost::mutex m;
boost::condition not_full;
boost::condition not_empty;
void writer()
{
}
void reader()
{
}
void main()
{
}
看了上面的文章,尽管有作者的解释,但还是没看明白。
经过不断的思考,才理解了boost::condition .wait为什么需要放在一个循环里
下面是我个人比较详细的分析。
比如有write A,write B和reader.
某个时刻,number等于5,并且在运行write A,write A阻塞在了wait函数上(这时会释放锁m),然后有可能reader开始运行,使number等于4,随后通过not_full.notify_one唤醒了write A,write A准备获取锁(write B也在等待获取锁),reader释放锁,由于线程运行的不确定性,这时有可能write B首先获取了锁使得number又等于5了。write B运行完毕释放锁,write A获得锁往下运行++number; 此时number等于6了,不在0和5范围内了。
如果write A获得锁后,通过while再检查一遍number,发现number等于5,就会又阻塞在wait函数上。这样一来,就能得到预期的结果了。