Какие именно ограждения предоставляются std :: memory_order в C ++?

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

  1. std :: memory_order_relaxed - забор не предусмотрен
  2. std :: memory_order_acquire - LoadLoad_LoadStore
  3. std :: memory_order_release - LoadStore_StoreStore
  4. std :: memory_order_consume - обычно равно memory_order_acquire
  5. std :: memory_order_acq_rel - LoadLoadLoadStore_LoadStoreStoreStore ???
  6. std :: memory_order_seq_cst - StoreLoad_StoreLoad ???

Насчет первых 4 элементов я не уверен. А вот про последние 2 элемента я ничего не знаю.

Кто-нибудь точно знает об этом?

Кроме того, мне нужно знать, в каком месте компилятор ставит забор памяти при использовании std :: atomic или std :: atomic_flag?

Насколько я понимаю, использование заборов с атомиком означает поставить забор и провести операцию. Я прав? Например:

atomic.load(std::memory_order_acquire);

значит применить забор memory_order_acquire и загружать данные атомарно?


person Joe Joe    schedule 10.02.2018    source источник
comment
Кроме того, мне нужно знать, в каком месте компилятор помещает ограждение памяти при использовании std :: atomic или std :: atomic_flag? Что вы имеете в виду, говоря в каком месте? Операции порядка памяти нигде не хранятся.   -  person Nicol Bolas    schedule 11.02.2018


Ответы (1)


Кто-нибудь точно знает об этом?

Конечно, существует множество источников, например Справочник по C ++:

memory_order_relaxed Расслабленная операция: нет ограничений на синхронизацию или упорядочение, налагаемых на другие операции чтения или записи, гарантируется только атомарность этой операции.

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

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

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

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

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

Также ознакомьтесь с atomic ‹> Презентация оружия от Херба Саттера, которая многое объясняет.

Также мне нужно знать, в какое место компилятор ставит забор памяти.

Это зависит от архитектуры. На некоторых архитектурах это не операция, на некоторых это префикс инструкции, на некоторых это будет специальная инструкция до / после загрузки / сохранения.

Существует статья под названием «Барьеры памяти: аппаратное обеспечение для Software Hackers ", который анализирует препятствия на многих архитектурах, если вам интересно.

Например: atomic.load(std::memory_order_acquire); означает применить memory_order_acquire ограждение и загрузить данные атомарно?

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

Но на некоторых платформах это может быть инструкция одного процессора. Например, на ARM есть инструкции загрузки (LDA) и сохранения-выпуска (STL).

person Andriy Berestovskyy    schedule 11.02.2018