Является ли значение "блокировки", даже определенного стандартом С++?

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

(Как) может ли блокировка атомарности влиять на семантику программы?

i.e., кроме вызова is_lock_free или atomic_is_lock_free, можно ли написать четко определенную программу, на поведение которой действительно влияет то, являются ли атомы блокировки?
Имеют ли эти функции даже смысловое значение? Или это просто практические хаки для написания отзывчивых программ, хотя язык никогда не обеспечивает гарантии времени в первую очередь?

Ответ 1

В стандарте С++ 11 термин "блокировка" не был определен хорошо, как указано в издать LWG # 2075.

С++ 14 Стандарт определяет, какие блокировки выполняются на языке С++ (N3927 одобрено).

Цитата С++ 14 1.10 [intro.multithread]/paragraph 4:

Исполнения атомных функций, которые либо определены как блокирующие (29.7), либо обозначены как блокирующие (29.4), являются блокируемыми исполнениями.

  • Если есть только один разблокированный поток, завершение блокировки в этом потоке завершается. [Примечание: одновременное выполнение потоков может препятствовать прогрессу без блокировки. Например, такая ситуация может возникать при реализации с привязкой к загрузке, зависящей от загрузки. Это свойство иногда называют обструкцией. - конечная нота]
  • Если одно или несколько незакрепленных исполнений запускаются одновременно, по крайней мере один должен завершиться. [Примечание. Некоторым реализациям трудно обеспечить абсолютные гарантии для этого, так как повторные и особенно непоправимые помехи от других потоков могут препятствовать продвижению вперед, например, путем многократного кражи строки кэша для несвязанных целей между блокировкой нагрузки и сохранением инструкции. Реализации должны обеспечивать, чтобы такие эффекты не могли бесконечно задерживать прогресс в ожидаемых условиях эксплуатации, и поэтому такие аномалии могут быть безопасно проигнорированы программистами. Вне этого международного стандарта это свойство иногда называют незакрепленным. - конечная нота]

Выше определения "lock-free" зависит от того, что ведет разблокированная нить. Стандарт С++ не определяет разблокированный поток напрямую, но 17.3.3 [defns.blocked] определяет заблокированный поток:

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


(Как) может ли блокировка атомарности влиять на семантику программы?

Я думаю, что ответ НЕТ, кроме обработчика сигнала как paxdiablo answer, когда "семантика программы" означает побочные эффекты атомных операций. Заблокированность атома влияет на прочность прогресса для целой программы многопоточности. Когда два (или более) потока одновременно выполняют блокирующие атомарные операции на одном объекте, по крайней мере одна из этих операций должна завершиться при любом худшем планировании потоков. Другими словами, планировщик потоков "злой" мог преднамеренно блокировать прогресс атомных операций на основе блокировки в теории.

Ответ 2

Существует, по крайней мере, одна семантическая разница.

В соответствии с C++11 1.9 Program execution /6:

Когда обработка абстрактной машины прерывается получением сигнала, значения объектов, которые не являются ни типом volatile std::sig_atomic_t, ни блокирующими атомными объектами, не указаны во время выполнения обработчика сигнала, а значение любой объект не в любом из эти две категории, модифицированные обработчиком, становятся undefined.

Другими словами, безопасно гадать с этими двумя категориями переменных, но следует избегать любого доступа или изменения ко всем другим категориям.

Конечно, вы можете утверждать, что он уже не является хорошо определенной программой, если вы вызываете неуказанное поведение / undefined, подобное этому, но я не совсем уверен, означает ли вы это или правильно сформированный (т.е. компилируемый).

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

  • наименьший адекватный тип данных, который был заблокирован.
  • больший тип данных, чем необходимо, если он был заблокирован, а меньший - нет.
  • общая область, полностью способная к условиям гонки, но в сочетании с atomic_flag (гарантированная блокировка) для управления доступом.

Такое поведение можно выбрать в момент компиляции или запуска на основе макросов ATOMIC_x_LOCK_FREE, чтобы, несмотря на то, что программа ведет себя одинаково независимо, выбирается оптимальный метод для этого поведения.

Ответ 3

Paxdiablo ответил неплохо, но может помочь какой-то фон.

"Свободный атомный атом" - это немного избыточная терминология. Точка атомных переменных, как они были первоначально изобретены, заключается в том, чтобы избежать блокировок, используя аппаратные гарантии. Но у каждой платформы есть свои ограничения, а С++ очень портативен. Таким образом, реализация должна эмулировать атомарность (обычно через библиотеку), используя мелкозернистые блокировки для атомных типов, которые на самом деле не существуют на аппаратном уровне.

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