Пожалуйста, смотрите следующий код:
std::mutex mutex;
std::condition_variable cv;
std::atomic<bool> terminate;
// Worker thread routine
void work() {
while( !terminate ) {
{
std::unique_lock<std::mutex> lg{ mutex };
cv.wait(lg);
// Do something
}
// Do something
}
}
// This function is called from the main thread
void terminate_worker() {
terminate = true;
cv.notify_all();
worker_thread.join();
}
Может ли произойти следующий сценарий?
terminate_worker()
;
terminate
в true
, а затем подал сигнал рабочему потоку.terminate
, На этом этапе изменение в terminate
сделано по главной ветке пока не видно, поэтому рабочий поток решает дождаться другого сигнала.Интересно, это когда-нибудь возможно. Как я понял, std::atomic
только гарантирует отсутствие гонки, но порядок памяти — это совсем другое. Вопросы:
terminate
не атомная переменная, а просто bool
? Или атомарность тут не причем?Спасибо.
Я не верю, что то, что вы описываете, возможно, так как cv.notify_all()
afaik (поправьте меня, если я ошибаюсь) синхронизируется с wait()
поэтому, когда рабочий поток просыпается, он увидит изменение terminate
,
Тем не мение:
Тупик может произойти следующим образом:
Рабочий поток (WT) определяет, что terminate
флаг все еще ложный.
Основной поток (MT) устанавливает terminate
флаг и звонки cv.notify_all()
,
join
и блоки.cv.wait()
) и блоки тоже. Решение:
Хотя вам не нужно держать блокировку во время вызова cv.notify, вы
terminate
(даже если это атомное)wait
произойдет, когда вы держите тот же замок. Вот почему существует форма wait
который выполняет эту проверку непосредственно перед отправкой потока в спящий режим.
Исправленный код (с минимальными изменениями) может выглядеть так:
// Worker thread routine
void work() {
while( !terminate ) {
{
std::unique_lock<std::mutex> lg{ mutex };
if (!terminate) {
cv.wait(lg);
}
// Do something
}
// Do something
}
}
// This function is called from the main thread
void terminate_worker() {
{
std::lock_guard<std::mutex> lg(mutex);
terminate = true;
}
cv.notify_all();
worker_thread.join();
}
Других решений пока нет …