С++, С++ 11, std:: atomic member functions

Я пытаюсь использовать std:: atomic library.

  • В чем разница между специализированным и неспециализированным атомарным функции-члены?
  • Какая разница (если есть) между следующими функциями?
  • operator = хранит значение в атомном объекте (функция публичного члена) v.s. store (С++ 11) атомарно заменяет значение атомного объекта неатомным аргументом (функция публичного участника)
  • оператор T() загружает значение из атомарного объекта (public member function) v.s. load (С++ 11) атомарно получает значение атомарного объекта (функция публичного члена).
  • оператор + = v.s. fetch_add
  • оператор - = v.s. fetch_sub
  • оператор & = v.s. fetch_and
  • оператор | = v.s. fetch_or
  • operator ^ = v.s. fetch_xor
  • В чем отличие объявления переменной как атома v.s.  неатомная переменная. Например, какой недостаток   std::atomic<int> x v.s. int x? Другими словами, сколько накладных расходов на атомную переменную?
  • У кого больше накладных расходов? Атомная переменная, v.s. нормальный  переменная, защищенная мьютексом?

Вот ссылка на мои quesitons. http://en.cppreference.com/w/cpp/atomic/atomic

Ответ 1

Не эксперт, но я постараюсь:

  • Специализации (для встроенных типов, таких как int) содержат дополнительные операции, такие как fetch_add. Неспециализированные формы (типы, определенные пользователем) не будут содержать эти данные.
  • operator= возвращает свой аргумент, store - нет. Кроме того, не-операторы позволяют указать порядок памяти. В стандарте указано, что operator= определяется в терминах store.
  • То же, что и выше, хотя оно возвращает значение load.
  • То же, что и выше
  • То же, что и выше
  • То же, что и выше
  • То же, что и выше
  • То же, что и выше
  • То же, что и выше
  • Они делают разные вещи. Это поведение undefined для использования int в том, как вы использовали бы std::atomic_int.
  • Вы можете предположить, что накладные расходы int <= std::atomic <= int and std::mutex, где <= означает "меньше накладных расходов". Поэтому это скорее всего лучше, чем блокировка с помощью мьютекса (особенно для встроенных типов), но хуже, чем int.

Ответ 2

В чем разница между специализированными и неспецифическими функциями атомных членов?

Как видно из обобщения этих классов на стандарте (§ 29.5), существует три разных набора функций-членов:

  • наиболее общий вариант обеспечивает только операции хранения, загрузки, обмена и сравнения;
  • специализации для интегральных типов обеспечивают атомные арифметические и побитовые операции, в дополнение к общим,
  • специализация для указателей предоставляет арифметические операции указателя в дополнение к общим.

Какая разница (если есть) между следующими функциями?

operator= хранит значение в атомном объекте (функция открытого члена) v.s. store (С++ 11) атомарно заменяет значение атомного объекта неатомным аргументом (функция публичного участника)

(...)

Основное функциональное различие заключается в том, что версии, не содержащие оператор (§ 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

Неоператорные формы являются предпочтительными, поскольку не всегда необходима последовательная согласованность и потенциально более дорогостоящая, чем другие порядки памяти. При тщательном анализе можно узнать, какие минимальные гарантии необходимы для правильной работы и выбрать один из менее ограничительных порядков памяти, что дает больше возможностей оптимизатору.

В чем недостаток объявления переменной как атома v.s. неатомная переменная. Например, какой недостаток std::atomic<int> x v.s. int x? Другими словами, сколько накладных расходов атомной переменной?

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

Использование регулярной переменной, когда требуется атомная переменная, может вводить расы данных и делает поведение undefined (§1.10/21):

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

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

У кого больше накладных расходов? Атомная переменная, v.s. нормальная переменная, защищенная мьютексом?

Нет никакой причины, чтобы атомная переменная имела больше накладных расходов, чем нормальная переменная, защищенная мьютексом: наихудший сценарий, атомная переменная реализована именно так. Но есть вероятность, что атомная переменная блокируется, что будет связано с меньшими затратами. Это свойство может быть установлено с помощью функций, описанных в стандарте в §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.

Ответ 3

Я не эксперт по этому поводу, но если я правильно понимаю, неспециализированные операции в вашей ссылке делают одну вещь атомарно, загружают, сохраняют, заменяют и т.д.

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