concurrency on boost::condition_variable::notify_one()
-
07-07-2021 - |
Domanda
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 ?
Soluzione
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:
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();
}
Note that this also protects against spurious returns from boost::condition_variable::wait()
. From the boost docs on boost::condition_variable::wait()
:
The thread will unblock when notified by a call to this->notify_one() or this->notify_all(), or spuriously.