Должен ли я использовать атомный для переменной «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(); }
- C ++ metafunction, чтобы определить, является ли тип вызываемым
- перебирать кортеж
- разрешение std :: chrono :: high_resolution_clock не соответствует измерениям
- Какие выражения дают ссылочный тип, когда к ним применяется метод decltype?
- std :: метод вызова streamа classа
- Унифицированная инициализация не копируется, когда объект не имеет данных
- Включена ли новая функция инициализации члена C ++ 11 при объявлении, что списки инициализации устарели?
- Как передать функцию шаблона в списке аргументов шаблона
- Вызов функции для каждого вариационного аргумента шаблона и массива
- Почему инициализатор C ++ 11 in-class не может использовать круглые скобки?
- Вычисление длины строки C во время компиляции. Это действительно констебр?
- C ++: Может ли макрос расширять «abc» на «a», «b», «c»?
- Как использовать пользовательский удаленный элемент с элементом std :: unique_ptr?
Должен ли я использовать атомный для переменной «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а.