В чем разница между специализированными и неспециализированными атомарными функциями-членами?
Как видно из краткого описания этих классов в стандарте (§29.5), существует три различныхнаборы функций-членов:
- самая общая предоставляет только операции сохранения, загрузки, обмена и сравнения-обмена;
- специализации для целочисленных типов обеспечивают атомарные арифметические и побитовые операции,в дополнение к общим;
- специализация для указателей обеспечивает арифметические операции с указателями в дополнение к общим.
В чем разница (если есть) междуследующие функции?
operator=
сохраняет значение в элементарном объекте (открытая функция-член), а store
(C ++ 11) атомарно заменяет значение атомарного объекта неатомарным аргументом (publicфункция-член)
(...)
Основное функциональное отличие состоит в том, что неоператорская версияons (§29.6.5, параграфы 9-17 и больше) имеют дополнительный параметр для указания желаемого порядка памяти (§29.3 / 1).Версии оператора используют последовательное упорядочение памяти последовательности:
void A::store(C desired, memory_order order = memory_order_seq_cst) volatile noexcept;
void A::store(C desired, memory_order order = memory_order_seq_cst) noexcept;
Требуется: Аргумент порядка не должен быть memory_order_consume
, memory_order_acquire
или memory_order_acq_rel
.
Эффекты: Атомно заменяет значение, на которое указывает объект или на него, значением желаемого.На память влияет значение order
.
C A::operator=(C desired) volatile noexcept;
C A::operator=(C desired) noexcept;
Эффекты: store(desired)
Возвращает: desired
Неоператорские формы предпочтительны, потому что последовательная согласованность не всегда необходима, и она потенциально дороже, чем другие упорядочения памяти.С помощью тщательного анализа можно выяснить, какие минимальные гарантии необходимы для правильной работы, и выбрать один из менее ограничивающих порядков памяти, что дает оптимизатору большую свободу действий.
Какова обратная сторона объявления переменной какатомарный против неатомарной переменной.Например, в чем минус std::atomic<int> x
против int x
?Другими словами, сколько стоят служебные данные атомарной переменной?
Использование атомарной переменной, когда регулярной переменной будет достаточно, ограничивает число возможных оптимизаций, поскольку атомарные переменные налагают дополнительные ограничения неделимости и (возможно) упорядочение памяти.
Использование обычной переменной, когда требуется атомарная переменная, может привести к гонкам данных, и это делает поведение неопределенным (§1.10 / 21):
Выполнениепрограммы содержит гонку данных , если она содержит два конфликтующих действия в разных потоках, по крайней мере одно из которых не является атомарным, и ни одно из них не происходит раньше другого.Любая такая гонка данных приводит к неопределенному поведению.
Накладные расходы на атомарную переменную зависят от качества реализации.В идеале атомарная переменная имеет нулевые накладные расходы, когда вам нужны атомарные операции.Когда вам не нужны атомарные операции, какие-либо накладные расходы могут не иметь значения: вы просто используете обычную переменную.
Какая из них имеет больше накладных расходов?Атомная переменная против нормальной переменной, защищенной мьютексом?
Нет никаких причин для того, чтобы у атомной переменной было больше служебных данных, чем у нормальной переменной, защищенной мьютексом: в худшем случаереализовано просто так.Но есть вероятность того, что атомная переменная не блокируется, что потребует меньше накладных расходов.Это свойство может быть установлено с помощью функций, описанных в стандарте в §29.6.5 / 7:
bool atomic_is_lock_free(const volatile A *object) noexcept;
bool atomic_is_lock_free(const A *object) noexcept;
bool A::is_lock_free() const volatile noexcept;
bool A::is_lock_free() const noexcept;
Возвращает: Истина, если операции объекта свободны от блокировки,иначе false.