Должен ли я использовать атомный для переменной «exit» bool?

Мне нужно установить флаг для выхода из другого streamа. Этот другой stream проверяет флаг выхода время от времени. Должен ли я использовать атомный для флага или достаточно простого bool и почему (с примером того, что может пойти не так, если я использую простой bool)?

#include  bool exit = false; void thread_fn() { while(!exit) { //do stuff if(exit) break; //do stuff } } int main() { auto f = std::async(std::launch::async, thread_fn); //do stuff exit = true; f.get(); } 

Должен ли я использовать атомный для переменной «exit» bool?

Да .

Либо используйте atomic , либо используйте ручную синхронизацию через (например) std::mutex . Ваша программа в настоящее время содержит гонку данных , причем один stream потенциально читает переменную, а другой stream записывает ее. Это неопределенное поведение.

В абзаце 1.10 / 21 стандарта C ++ 11:

Выполнение программы содержит гонку данных, если она содержит два конфликтующих действия в разных streamах, по крайней мере один из которых не является атомарным, и не происходит до другого. Любая такая гонка данных приводит к неопределенному поведению .

Определение « противоречия » приведено в пункте 1.10 / 4:

Две оценки выражений противоречат друг другу, если один из них изменяет местоположение памяти (1.7), а другой получает или изменяет одну и ту же ячейку памяти.

Да, у вас должна быть синхронизация. Самый простой способ – это, как вы говорите, с atomic .

Формально, как говорит @AndyProwl, в определении языка говорится, что не использование атома здесь дает неопределенное поведение. Для этого есть веские причины.

Во-первых, чтение или запись переменной может быть прервано на полпути с помощью переключателя streamа; другой stream может видеть частично записанное значение, или если он изменяет значение, исходный stream будет видеть смешанное значение. Во-вторых, когда два streamа работают на разных ядрах, у них есть отдельные кэши; запись значения хранит его в кеше, но не обновляет другие кеши, поэтому stream может не видеть значение, написанное другим streamом. В-третьих, компилятор может реорганизовать код на основе того, что он видит; в примере кода, если ничто внутри цикла не изменит значение exit , у компилятора нет причин подозревать, что значение изменится; он может включить цикл while(1) .

Atomics адресует все три из этих проблем.

фактически, в этом конкретном примере ничего не происходит с обычным bool. единственным уведомлением является объявление переменной bool exit как изменчивой, чтобы сохранить ее в памяти. как архитектуры CISC, так и RISC реализуют bool read / write как строго атомную инструкцию процессора. также современные многоядерные процессоры имеют расширенный интеллектуальный кэш-модуль. поэтому никаких барьеров памяти не требуется. стандартная цитата не подходит для данного конкретного случая, потому что она имеет дело с единственной записью и чтением только из одного streamа.

  • push_back vs emplace_back
  • Почему стандарт различает инициализацию прямого списка и инициализацию списка копий?
  • C ++ 11: Оператор на основе диапазона: срок действия «range-init»?
  • Как обнаружить поддержку C ++ 11 компилятора с помощью CMake
  • Какой тип lambda выведен с помощью «auto» в C ++ 11?
  • Будет ли std :: string всегда заканчиваться на null в C ++ 11?
  • Разрешение перегрузки с помощью std :: function
  • Почему этот компилятор кода C ++ (не-void функция не возвращает значение)
  • Требует ли std :: mt19937 разминки?
  • Компиляция C ++ 11 с g ++
  • Что делает этот код вариационного шаблона?
  • Давайте будем гением компьютера.