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 ?

È stato utile?

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top