【问题标题】:concurrency on boost::condition_variable::notify_one()boost::condition_variable::notify_one() 上的并发
【发布时间】:2012-10-15 13:30:27
【问题描述】:

我有一个异步处理任务的“引擎”,对于一个任务,我想等到该任务处理完毕。

boost::condition_variable cvWorkDone;

DoSomeWork()
{
   PostAsyncJob(DoWorkAsync)   // is a boost::asio::post

   boost::mutex::scoped_lock lock(mtxWorkDoneCv);
   cvWorkDone.wait(lock);
}


DoWorkAsync()
{
   // do some work ...

   cvWorkDone.notify_one();
}

问题是上面的代码有一个竞争条件。如果DoWorkAsync()DoSomeWork() 等待之前通知boost::condition_variable 怎么办?

我看到boost::condition_variable::wait 有第二个参数,一个布尔值,可以用来实现类似的东西

bool bWait;

DoSomeWork()
{
   bWait = true;
   PostAsyncJob(DoWorkAsync)   // boost::asio::post

   boost::mutex::scoped_lock lock(mtxWorkDoneCv);
   cvWorkDone.wait(lock, bWait);
}


DoWorkAsync()
{
   // do some work ...
   boost::mutex::scoped_lock lock(mtxWorkDoneCv);
   cvWorkDone.notify_one();      
   bWait = false;
}

但并发仍然存在......我该如何解决这个问题?

【问题讨论】:

    标签: c++ boost synchronization race-condition condition-variable


    【解决方案1】:

    由于条件变量不维护关于它们是否已发出信号的状态,因此您需要维护状态,以应对可能导致单独发出信号的条件变量的任何原因(在某些情况下,例如队列、发出信号的条件变量的原因可以异步消失)。所以你的代码中可能会有这样的东西:

    boost::condition_variable cvWorkDone;
    bool workdone = false;
    
    DoSomeWork()
    {
       PostAsyncJob(DoWorkAsync)   // is a boost::asio::post
    
       boost::mutex::scoped_lock lock(mtxWorkDoneCv);
       while (!workdone) {
          cvWorkDone.wait(lock);
       }
    }
    
    
    DoWorkAsync()
    {
       // do some work ...
    
       {   
          boost::mutex::scoped_lock lock(mtxWorkDoneCv);
          workdone = true;
       }
       cvWorkDone.notify_one();
    }
    

    请注意,这也可以防止来自boost::condition_variable::wait() 的虚假返回。来自boost::condition_variable::wait() 上的 boost 文档:

    当调用 this->notify_one() 或 this->notify_all(),或虚假,线程将解除阻塞。

    【讨论】:

    • 为什么要解决并发问题? workdone = true;cvWorkDone.notify_one(); 可以在 !workdonevWorkDone.wait(lock); 之前执行。并且主线程将等待一个永远不会到来的 notify_one。
    • 当调用 this->notify_one() 或 this->notify_all(),或虚假,线程将解除阻塞。一点都不好听。
    • 这解决了并发问题,因为workdone 仅在持有互斥锁时才会更新和检查。当且仅当DoAsyncWork() 尚未到达workdone = true 语句时,服务员才能到达cvWorkDone.wait(lock) 语句。相反,如果DoWorkAsync() 在服务员到达while (!workdone) 之前设置workdone = true,那么服务员会注意到workdone 已设置,并且不会费心等待条件变量。重申一下,那里没有竞争,因为线程必须获取互斥锁才能设置或检查workdone
    • boost::condition_variable::wait() 可能会有虚假唤醒,因为这是 boost 使用的底层系统机制的常见行为。有关条件变量可能以这种方式运行的基本原理,请参阅stackoverflow.com/questions/8594591/…。因此,通常,您需要在条件变量“信号”的条件下循环。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多