параллелизм в boost :: condition_variable :: notify_one ()

У меня есть «движок», который асинхронно обрабатывает задачи, и для одной задачи я хочу подождать, пока эта задача не будет обработана.

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;
}

но параллелизм все еще там … Как я могу решить это?

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():

Поток будет разблокирован, когда получит уведомление посредством вызова this-> notify_one () или this-> notify_all (), или с явным.

3

Другие решения

Других решений пока нет …