Разве atomic<bool>
не является избыточным, потому что bool
является атомарным по своей природе? Я не думаю, что возможно иметь частично измененное логическое значение. Когда мне действительно нужно использовать atomic<bool>
вместо bool
?
Когда мне действительно нужно использовать atomic‹bool› вместо bool?
Ответы (6)
Ни один тип в C++ не является "атомарным по своей природе", если только он не является std::atomic*
чем-то. Это потому, что так сказано в стандарте.
На практике фактические аппаратные инструкции, которые выдаются для управления std::atomic<bool>
, могут (а могут и не быть) такими же, как и для обычного bool
, но атомарность — это более широкое понятие с более широкими разветвлениями (например, ограничения на переупорядочивание компилятора). Кроме того, некоторые операции (например, отрицание) перегружаются атомарной операцией, чтобы создать на аппаратном уровне инструкции, явно отличающиеся от нативной, неатомарной последовательности чтения-модификации-записи неатомарной переменной.
std::atomic_flag
является единственным исключением, хотя его имя также начинается с атома.
- person yngccc; 01.05.2013
std::atomic*
, а не std::atomic<*>
.
- person Sebastian Mach; 17.10.2018
Помните о барьерах памяти. Хотя частично изменить bool
может быть невозможно, возможно, что многопроцессорная система имеет эту переменную в нескольких копиях, и один поток может видеть старое значение даже после того, как другой поток изменил его на новое. Atomic вводит барьер памяти, поэтому это становится невозможным.
volatile
может решить проблему многопроцессорности?
- person Vincent Xue; 29.06.2015
volatile
в Java. Ключевое слово volatile
в Java управляет ограничениями памяти, но его поведение сильно отличается от ключевого слова volatile
в C, которое этого не делает. Этот вопрос объясняет разницу далее.
- person Pace; 19.12.2016
std::memory_order_relaxed
, чтобы получить атомарность без упорядочения. Этот ответ совершенно неверен: барьеры не создают атомарности, потому что, например, они не предотвращают появление хранилища из другого потока между tmp=var; tmp++; var=tmp;
. Чтобы преобразовать эту последовательность в атомарный RMW, необходимы специальные инструкции ЦП. См. также Может ли num++ быть атомарным для 'int num'?
- person Peter Cordes; 03.07.2019
atomic
по умолчанию использует последовательную согласованность, так и скажите. Это не требуется для атомарности, а конфликтующие значения в кеше для одной и той же переменной невозможны: когерентность кеша MESI предотвращает это. atomic
подразумевает некоторые из тех же вещей, что и volatile
, поэтому компилятор не поднимает значение переменной в регистр. Это непоследовательно.
- person Peter Cordes; 03.07.2019
atomic<T>
действительно делает в обычных системах, так это не позволяет компилятору сохранять значение в закрытом для потока регистре.
- person Peter Cordes; 05.07.2019
Атомарные типы C++ имеют дело с тремя потенциальными проблемами. Во-первых, чтение или запись могут быть прерваны переключением задач, если операция требует более одной операции шины (и это может случиться с bool
, в зависимости от того, как это реализовано). Во-вторых, чтение или запись могут повлиять только на кеш, связанный с процессором, выполняющим операцию, а другие процессоры могут иметь другое значение в своем кеше. В-третьих, компилятор может изменить порядок операций, если они не влияют на результат (ограничения немного сложнее, но пока этого достаточно).
Вы можете решить каждую из этих трех проблем самостоятельно, делая предположения о том, как реализуются используемые вами типы, явно очищая кэши и используя параметры компилятора для предотвращения переупорядочения (и, нет, volatile
не делает этого). это, если ваша документация компилятора не говорит об этом).
Но зачем проходить через все это? atomic
позаботится об этом за вас и, вероятно, сделает это лучше, чем вы сами.
while(!var) {}
в if(!var) infloop();
. Эта часть atomic
похожа на то, что делает volatile
: всегда перечитывается из памяти (которая кэшируется, но связна).
- person Peter Cordes; 03.07.2019
volatile
+ барьеры. И вам понадобится встроенный ассемблер для атомарных элементов RMW, таких как var += 1;
, чтобы он был одним атомарным приращением вместо атомарной загрузки, приращением внутри ЦП, а затем отдельным атомарным хранилищем.
- person Peter Cordes; 03.07.2019
atomic
, и что их всего 3. ISO C++ даже не упоминает кеши; это на вас, поэтому я думаю, что справедливо критиковать ваш выбор того, о чем говорить, что касается тайников. Вы не технически неправы, просто ИМО вводит в заблуждение.
- person Peter Cordes; 05.07.2019
atomic<bool>
позаботится за вас, если это проблема в целевой системе. Даже несмотря на то, что это не относится ни к одной реализации C++, о которой я знаю, если читатель не знал об этом, то он определенно не готов сворачивать свои собственные атомарные блоки поверх volatile
или барьеров памяти, специфичных для компилятора.
- person Peter Cordes; 05.07.2019
std::atomic<bool>
дает вам как минимум 2 другие вещи, о которых вы не упомянули: четко определенное поведение, если другой поток изменяет значение, которое вы читаете в цикле. (Таким образом, это имеет то же самое, что и volatile
: принудительное повторное чтение из памяти). И сделайте операции чтения-изменения-записи, такие как b ^= 1;
atomic. За исключением того, что atomic<bool>
не имеет функции инвертирования, но есть b.compare_exchange_weak
или .exchange
, которые являются атомарными. например на x86 вы получаете lock cmpxchg
вместо просто загрузки/ветвления или чего-то еще. Как атомарно отменить std::atomic_bool?
- person Peter Cordes; 05.07.2019
volatile
не дает вам четко определенное поведение для этого в ISO C++. Только в определенных реализациях (таких как GNU C для известного набора ISA) вы можете с пользой накатывать свои собственные атомарные вычисления поверх volatile
, игнорируя тот факт, что технически это UB, как и ядро Linux. Я должен был сказать и вместо или вещей, определяемых реализацией. Я думаю, что на практике вам будет трудно найти реализацию, в которой volatile
будет ломаться для этого; как я уже сказал, я не думаю, что существуют какие-либо реализации C++ на несогласованном оборудовании с общей памятью, и это очень нестандартно.
- person Peter Cordes; 05.07.2019
atomic
, а не о volatile
. Я утверждаю, что atomic
не дает вам поведения, при котором один поток, читающий переменную, увидит новое значение после того, как другой поток запишет его, теоретически. На практике это происходит из-за проблемы QoI и потому, что оптимизация, которая сломает это, маловероятна.
- person BeeOnRope; 05.07.2019
if(!b) infloop();
было эквивалентно while(!b){}
согласно правилу "как если", вам нужно решить, что все бесконечное число операций чтения b
являются непрерывными в глобальном порядке операций чтения и записи для b
. то есть все они происходят до любой возможной записи из другого потока. Я предполагаю, что теоретически это возможно для реализации DeathStation 9000, но совершенно очевидно, что это не намерение стандарта. Это может даже не соответствовать стандарту в зависимости от порядка запуска программы своих потоков.
- person Peter Cordes; 05.07.2019
atomic<>
в стандарте ISO не полностью гарантирует очистку кеша в непоследовательной системе.
- person Peter Cordes; 05.07.2019
Рассмотрим операцию сравнения и обмена:
bool a = ...;
bool b = ...;
if (a)
swap(a,b);
После того, как мы прочитаем a, мы получим true, другой поток может прийти и установить false, затем мы меняем местами (a,b), так что после выхода b становится false, даже несмотря на то, что обмен был сделан.
Используя std::atomic::compare_exchange
, мы можем выполнить всю логику if/swap атомарно, чтобы другой поток не мог установить значение false между if и swap (без блокировки). В таком случае, если обмен был сделан, то b должно быть ложным на выходе.
Это всего лишь один пример атомарной операции, которая применяется к типу с двумя значениями, такому как bool.
Атомарные операции — это больше, чем просто разорванные значения, поэтому, хотя я согласен с вами и другими авторами, что я не знаю о среде, в которой возможно разорванное bool
, на карту поставлено нечто большее.
Херб Саттер сделал отличный доклад об этом, который вы можете посмотреть в Интернете. Предупреждаю, это долгий и запутанный разговор. Херб Саттер, Атомное оружие. Проблема сводится к тому, чтобы избежать гонок данных, потому что это позволяет создать иллюзию последовательной согласованности.
Атомарность некоторых типов зависит исключительно от базового оборудования. Каждая архитектура процессора имеет разные гарантии атомарности определенных операций. Например:
Процессор Intel486 (и более новые процессоры с тех пор) гарантирует, что следующие основные операции с памятью всегда будут выполняться атомарно:
- Чтение или запись байта
- Чтение или запись слова, выровненного по 16-битной границе
- Чтение или запись двойного слова, выровненного по 32-битной границе
Другие архитектуры имеют другие спецификации, в которых операции являются атомарными.
C++ — это язык программирования высокого уровня, который стремится абстрагироваться от базового оборудования. По этой причине стандарт просто не может позволить полагаться на такие низкоуровневые предположения, иначе ваше приложение не будет переносимым. Соответственно, все типы-примитивы в C++ поставляются с atomic
аналогами стандартной библиотеки, совместимой с C++11, из коробки.
atomic
как бы включает это свойство volatile
, поэтому while(!var){}
не может оптимизироваться в if(!var) infinite_loop();
. См. раздел Программирование MCU — оптимизация C++ O2 прерывается при выполнении цикла
- person Peter Cordes; 03.07.2019
atomic<bool>
, чтобы избежать условий гонки. Состояние гонки возникает, если два потока обращаются к одной и той же ячейке памяти, и хотя бы один из них является операцией записи. Если ваша программа содержит условия гонки, поведение не определено. - person nosid   schedule 01.05.2013int
, где вы копируете каждый байт или слово этого значения по отдельности. Поэтому не должно быть условий гонки, если запись уже является атомарной. - person Robert Harvey   schedule 01.05.2013sizeof(bool)
определяется реализацией и предположительно может быть > 1, поэтому в некоторых случаях возможно, что он не является атомарным. - person Paul R   schedule 01.05.2013