对“关于boost::condition的用法”文章的个人的分析

来源:互联网 发布:js中怎么定义二维数组 编辑:程序博客网 时间:2024/06/05 13:48

 首先我们看只有一个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()
{
    while (1) {
        boost::mutex::scoped_lock sl(m);
        if (number == 5) {
            not_full.wait(m);
        }
        ++number;
        std::cout << "after w: " << number << std::endl;
        not_empty.notify_one();
    }
}

void reader()
{
    while (1) {
        boost::mutex::scoped_lock sl(m);
        if (number == 0) {
            not_empty.wait(m);       
        }
        --number;
        std::cout << "after r: " << number << std::endl;
        not_full.notify_one();
    }
}

void main()
{
    boost::thread trd1(&writer);
    boost::thread trd2(&reader);
    trd1.join();
    trd2.join();
}


运行之后程序一切如常,0-5的一些数字会打印出来。

但是当另外一个write加入战局的时候,情况变得有些微妙的不同,如果我们只是在main里面加入一个writer,其他部分保持不变的话,你会看到一些错误的数字出现:

void main()
{
    boost::thread trd1(&writer);
    boost::thread trd11(&writer);
    boost::thread trd2(&reader);
    trd1.join();
    trd11.join();
    trd2.join();
}


究其原因是:在reader->notify_one之后并在socped_lock解锁之前,在not_full上等待的writer A被唤起,然后reader解锁,此时可能另外一个writer B先获得锁而直接增加了number。在writeB 解锁后, writerA获得锁,但此时not_full条件已经被破坏。所以一种做法是再次检查该条件,也就是这样:

while (number == 5) {
    not_full.wait(m);
}


对于多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()
{
    while (1) {
        boost::mutex::scoped_lock sl(m);
        while (number == 5) {
            not_full.wait(m);
        }
        ++number;
        std::cout << "after w: " << number << std::endl;
        not_empty.notify_one();
    }
}

void reader()
{
    while (1) {
        boost::mutex::scoped_lock sl(m);
        while (number == 0) {
            not_empty.wait(m);       
        }
        --number;
        std::cout << "after r: " << number << std::endl;
        not_full.notify_one();
    }
}

void main()
{
    boost::thread trd1(&writer);
    boost::thread trd11(&writer);
    boost::thread trd2(&reader);
    boost::thread trd22(&reader);
    trd1.join();
    trd11.join();
    trd2.join();
    trd22.join();
}

 

 

看了上面的文章,尽管有作者的解释,但还是没看明白。

经过不断的思考,才理解了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函数上。这样一来,就能得到预期的结果了。

原创粉丝点击