namespace std { enum memory_order { memory_order_relaxed, memory_order_consume, memory_order_acquire, memory_order_release, memory_order_acq_rel, memory_order_seq_cst }; }
Перечисление memory_order определяет подробный регулярный (неатомарный) порядок синхронизации памяти, как определено в, [intro.multithread] и может предусматривать порядок операций. Его перечисляемые значения и их значения следующие:
memory_order_relaxed: никакая операция не заказывает память.
memory_order_release, memory_order_acq_relи memory_order_seq_cst: операция сохранения выполняет операцию освобождения затронутой области памяти.
memory_order_consume: операция загрузки выполняет операцию потребления в затронутой области памяти. [ Note: Предпочтение memory_order_acquire, которое обеспечивает более сильные гарантии, чем memory_order_consume. Реализации сочли невозможным обеспечить производительность лучше, чем у memory_order_acquire. Пересмотр спецификации находится на рассмотрении. ] — end note
memory_order_acquire, memory_order_acq_relи memory_order_seq_cst: операция загрузки выполняет операцию получения в затронутой области памяти.
[ Note: Указание атомарных операций memory_order_relaxed ослаблено в отношении упорядочения памяти. Реализации должны по-прежнему гарантировать, что любой заданный атомарный доступ к конкретному атомарному объекту будет неделимым по отношению ко всем другим атомарным доступам к этому объекту. ] — end note
Атомарная операция, A которая выполняет операцию выпуска над атомарным объектом, M синхронизируется с атомарной операцией, B которая выполняет операцию получения M и берет свое значение из любого побочного эффекта в последовательности выпуска, озаглавленной A.
Должен быть единый общий порядок S для всех memory_order_seq_cst операций, соответствующий порядку «происходит до» и порядкам модификации для всех затронутых местоположений, так что каждая memory_order_seq_cst операция, B которая загружает значение из атомарного объекта, M наблюдает одно из следующих значений:
результат последней модификации A из того, M что предшествует B в S, если она существует, или
если A существует, результат некоторой модификации M этого не происходит memory_order_seq_cst и не происходило раньше A, или
если A не существует, результат некоторой модификации M этого не существует memory_order_seq_cst.
[ Note: Хотя явно не требуется S включать блокировки, его всегда можно расширить до порядка, который включает операции блокировки и разблокировки, поскольку упорядочение между ними уже включено в порядок «происходит до». ] — end note
Для атомарной операции, B которая считывает значение атомарного объекта M, если есть memory_order_seq_cst забор, X упорядоченный ранее B, то B наблюдает либо последнюю memory_order_seq_cst модификацию M предыдущего X в общем порядке, S либо более позднюю модификацию M в его порядке модификации.
Для атомарных операций A и B для атомарного объекта M, где A модифицирует M и B принимает свое значение, если есть memory_order_seq_cst ограждение X , которое A упорядочено до X и B следует X за ним S, то B наблюдает либо эффекты, A либо последующие модификации M в порядке его модификации.
Для атомарных операций A и B на атомарном объекте M, где A модифицирует M и B принимает свое значение, если есть memory_order_seq_cst ограждения, X и Y такое, что A упорядочено до X, Y упорядочено до Bи X предшествует Y в S, то B наблюдает либо эффекты, A либо более позднюю модификацию M в порядке его модификации .
Для атомных модификаций A и B атомного объекта M, B происходит позже , чем A в порядке модификации , M если:
есть memory_order_seq_cst забор X таким образом, что A секвенировали до того X, и X предшествует B в S, или
есть memory_order_seq_cst забор Y таким образом, что Y секвенировали до того B, и A предшествует Y в S, или
есть memory_order_seq_cst заборы X и Y такие, что A упорядочены до X, Y упорядочены до Bи X предшествуют Y в S.
[ Note: memory_order_seq_cst обеспечивает последовательную согласованность только для программы, которая свободна от гонок данных и использует исключительно memory_order_seq_cst операции. Любое использование более слабого порядка приведет к аннулированию этой гарантии, если не будут приняты особые меры предосторожности. В частности, memory_order_seq_cst заборы обеспечивают полный порядок только самих заборов. Как правило, ограждения не могут использоваться для восстановления последовательной согласованности атомарных операций с более слабыми спецификациями упорядочивания. ] — end note
Реализации должны гарантировать, что не вычисляются «неожиданные» значения, которые циклически зависят от их собственных вычислений.
[ Note: Например, x и y изначально равна нулю,
// Thread 1:
r1 = y.load(memory_order_relaxed);
x.store(r1, memory_order_relaxed);
// Thread 2:
r2 = x.load(memory_order_relaxed);
y.store(r2, memory_order_relaxed);
не следует производить r1 == r2 == 42, так как хранение от 42 до y возможно только при хранении в x магазинах 42, которое циклически зависит от магазина для y хранения 42. Обратите внимание, что без этого ограничения такое выполнение возможно. ] — end note
[ Note: Рекомендация аналогичным образом запрещает r1 == r2 == 42 в следующем примере с снова x и y снова с нулевым значением:
// Thread 1:
r1 = x.load(memory_order_relaxed);
if (r1 == 42) y.store(42, memory_order_relaxed);
// Thread 2:
r2 = y.load(memory_order_relaxed);
if (r2 == 42) x.store(42, memory_order_relaxed);
— end note ]
Атомарные операции чтения-изменения-записи всегда должны считывать последнее значение (в порядке модификации), записанное перед записью, связанной с операцией чтения-изменения-записи.
Реализации должны делать атомарные хранилища видимыми для атомарных загрузок в течение разумного промежутка времени.
template <class T>
T kill_dependency(T y) noexcept;
Effects: Аргумент не carry a dependency соответствует возвращаемому значению.