Подтвердить что ты не робот

Что такое std:: atomic?

Я понимаю, что std::atomic<> - это атомный объект. Но атомный, в какой степени? Насколько я понимаю, операция может быть атомарной. Что именно подразумевается под атомами объекта? Например, если есть два потока, одновременно выполняющих следующий код

a = a + 12;

Тогда вся операция (скажем, add_twelve_to (int)) атомная? Или изменения, внесенные в переменную атомную (so operator =())?

4b9b3361

Ответ 1

Каждый экземпляр и полная специализация std:: atomic < > представляют тип, что разные потоки могут одновременно работать, не поднимая undefined поведение:

Объекты атомных типов являются единственными объектами С++, свободными от гонок данных; то есть, если один поток записывает на атомный объект, а другой поток читает его, поведение корректно определено.

Кроме того, доступ к атомным объектам может устанавливать межпоточную синхронизацию и упорядочивать неатомные обращения к памяти, как указано в std::memory_order.

std::atomic<> обертывает операции, которые в pre-С++ 11 раз выполнялись с использованием (например) взаимосвязанных функций с MSVC или атомные bultins в случае GCC.

Кроме того, std::atomic<> дает вам больше контроля, позволяя различные порядки памяти, которые определяют ограничения синхронизации и упорядочения. Если вы хотите больше узнать о модели атома и модели памяти С++ 11, эти ссылки могут быть полезными:

Обратите внимание, что для типичных случаев использования вы, вероятно, используете перегруженные арифметические операторы или другой набор из них:

std::atomic<long> value(0);
value++; //This is an atomic op
value += 5; //And so is this

Эти операции будут выполняться с std::memory_order_seq_cst, так как это порядок по умолчанию для всех атомных операций в С++ 11. Он гарантирует последовательную согласованность (общее глобальное упорядочение) между всеми атомными операциями.

Однако в некоторых случаях это может не потребоваться (и ничего не приходит бесплатно), поэтому вы можете использовать более явную форму:

std::atomic<long> value(0);
value.fetch_add(1, std::memory_order_relaxed); //Atomic, but there are no synchronization or ordering constraints
value.fetch_add(5, std::memory_order_release); //Atomic, performs 'release' operation; guarantees, that no memory accesses in the current thread can be reordered after this store

Теперь, ваш пример:

a = a + 12;

не будет оценивать один атомный op: это приведет к a.load() (который является атомом), затем добавление между этим значением и 12 и a.store() (также атомарным) конечного результата.

Однако, если вы напишете a += 12, это будет атомная операция (как я уже отмечал ранее).

Что касается вашего комментария:

Регулярный int имеет атомные нагрузки и запасы. Какова точка его обертывания с помощью atomic<>

Ваше утверждение верно только для x86. Существуют и другие архитектуры, которые не обеспечивают такую ​​гарантию. std::atomic<> - это что-то, что гарантировано будет атомарным на каждой платформе.

Ответ 2

Я понимаю, что std::atomic<> делает объект атомарным.

Это вопрос перспективы... вы не можете применить его к произвольным объектам и заставить их операции стать атомарными, но можно использовать предоставленные специализации для (большинства) интегральных типов и указателей.

a = a + 12;

std::atomic<> не использует (используйте выражения шаблонов) для упрощения этой операции для одной атомной операции, вместо этого член operator T() const volatile noexcept выполняет атомный load() из a, затем добавляется двенадцать, а operator=(T t) noexcept выполняет store(t).