Рассмотрим следующую цитату о std::condition_variable
из cppreference :
Класс condition_variable
является примитивом синхронизации, который можно использовать для блокировки потока или нескольких потоков. в то же время, пока другой поток не изменит общую переменную (условие ) и не уведомит condition_variable
.
поток, который намеревается изменить переменная должна
- получить
std::mutex
(обычно через std::lock_guard
) - выполнить модификацию, пока удерживается блокировка
- выполнить
notify_one
или notify_all
в std::condition_variable
(блокировка не требуется для уведомления)
Даже если общая переменная - atomi c, она должна быть измененным под мьютексом , чтобы правильно опубликовать sh модификацию ожидающего потока.
Примерный типичный сценарий этого подхода следующий:
// shared (e.d., global) variables:
bool proceed = false;
std::mutex m;
std::condition_variable cv;
// thread #1:
{
std::unique_lock<std::mutex> l(m);
while (!proceed) cv.wait(l); // or, cv.wait(l, []{ return proceed; });
}
// thread #2:
{
std::lock_guard<std::mutex> l(m);
proceed = true;
}
cv.notify_one();
Однако @Tim в этот вопрос придумал (добрый - альтернативы Academi c):
std::atomic<bool> proceed {false}; // atomic to avoid data race
std::mutex m;
std::condition_variable cv;
// thread #1:
{
std::unique_lock<std::mutex> l(m);
while (!proceed) cv.wait(l);
}
// thread #2:
proceed = true; // not protected with mutex
{ std::lock_guard<std::mutex> l(m); }
cv.notify_one();
Очевидно, что она не соответствует требованиям приведенной выше цитаты cppreference, поскольку proceed
общая переменная (atomi c в этом case) не изменяется под мьютексом .
Вопрос в том, верен ли этот код. На мой взгляд, так и есть, поскольку:
Первый вариант - !proceed
в while (!proceed)
оценивается как false . В этом случае cv.wait(l);
вообще не вызывается.
Второй вариант заключается в том, что !proceed
в while (!proceed)
оценивается как true . В этом случае cv.notify_one()
не может произойти до тех пор, пока поток # 1 не войдет в cv.wait(l);
.
Я что-то упустил или неверная ссылка в этом отношении? (Для Например, есть ли какие-то проблемы с переупорядочением?)
И что, если proceed = true;
будет изменен на proceed.store(true, std::memory_order_relaxed);
?