thread.join()
и promise.set_value()
/ future.wait()
гарантируют наличие барьеров памяти.
Использование atomic_bool
необходимо, если вы не хотите, чтобы компилятор переупорядочивал булеву проверку или присваивание с другим кодом. Но в этом конкретном случае вы можете использовать не атомарный bool
. Это flag
будет гарантированно равным true
в момент проверки, если вы не используете его в каком-либо другом месте, так как назначение и проверка находятся на противоположных сторонах точки синхронизации (fut.get()
) (принудительно компилятор для загрузки действительного flag
значения) и функция runInThreadPoolBlocking()
гарантированно завершится только после выполнения лямбды.
Цитата из cplusplus.com для future::get()
, например:
Данные гонки
Будущий объект изменен. Доступ к общему состоянию осуществляется как
атомарная операция (без гонок данных).
То же самое для promise::set_value()
. Помимо прочего
... атомарная операция (без гонок данных) ...
означает, что ни одна из конфликтующих оценок не предшествует другой (строгий порядок в памяти).
То же самое делают все std::
многопоточные примитивы и инструменты синхронизации, где вы ожидаете, что некоторые операции будут выполняться только до или после точки синхронизации (например, std::mutex::lock()
или unlock()
, thread::join()
и т. Д.).
Обратите внимание, что любые операции над самим объектом потока не синхронизируются с thread::join()
(в отличие от операций внутри потока, который он представляет).