У меня есть «движок», который асинхронно обрабатывает задачи, и для одной задачи я хочу подождать, пока эта задача не будет обработана.
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()
уведомляет boost::condition_variable
до DoSomeWork()
ждет этого?
я вижу это boost::condition_variable::wait
имеет второй параметр, bool, который может быть использован для реализации чего-то вроде этого
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;
}
но параллелизм все еще там … Как я могу решить это?
Поскольку условные переменные не поддерживают состояние о том, были ли они сигнализированы или нет, необходимо поддерживать состояние по какой-либо причине, по которой переменная условия должна сигнализироваться отдельно (в некоторых случаях, таких как очереди, причина переменная условия, которая должна быть передана, может исчезнуть асинхронно). Таким образом, у вас может быть что-то вроде этого в вашем коде:
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()
:
Поток будет разблокирован, когда получит уведомление посредством вызова this-> notify_one () или this-> notify_all (), или с явным.
Других решений пока нет …