I have an “engine” that asynchronously process tasks and for one task I want to wait until that task is processed.
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();
}
The problem is that the code above has a race condition. What if DoWorkAsync() notifies the boost::condition_variable before DoSomeWork() waits for it ?
I see that boost::condition_variable::wait has a second parameter, a bool that can be used to implement something like this
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;
}
but the concurrency is still there … How can I solve this ?
Since condition variables don’t maintain state about whether they’ve been signaled or not, you need to maintain the state for whatever might be the reason for the condition variable to be signaled separately (in some cases, such as queues, the reason for a condition variable to be signaled can go away asynchronously). So you might have something like this in your code:
Note that this also protects against spurious returns from
boost::condition_variable::wait(). From the boost docs onboost::condition_variable::wait():