Пространства имён
Варианты
Действия

std::memory_order

Материал из cppreference.com
< cpp‎ | atomic


Определено в заголовочном файле <atomic>
enum memory_order {

    memory_order_relaxed,
    memory_order_consume,
    memory_order_acquire,
    memory_order_release,
    memory_order_acq_rel,
    memory_order_seq_cst

};
(начиная с C++11)

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

Для атомарных операций по умолчанию библиотекой предоставляется последовательно согласованное упорядочение (sequentially consistent ordering) (см обсуждение ниже). Такое поведение может повредить быстродействию, но атомарным операциям библиотеки может быть передан дополнительный std::memory_order аргумент, чтобы указать точные ограничения, помимо атомарности, которые компилятор и процессор должны обеспечить для этой операции.

Содержание

[править] Константы

Заголовочный файл <atomic>
Значение Объяснение
memory_order_relaxed Ослабленное(Relaxed) упорядочение: отсутствуют ограничения синхронизации и упорядочения, для данной операции требуется только атомарность.
memory_order_consume Операция загрузки с этим упорядочением памяти выполняет операцию поглощения (consume) над задействованной областью памяти: предыдущие записи в зависимую от данных область памяти, сделанные потоком, выполнившим операцию освобождения (release), становятся видимыми для цепочки зависимостей данного потока.
memory_order_acquire Операция загрузки с этим упорядочением памяти выполняет операцию захвата (acquire) над задействованной областью памяти: предыдущие записи, сделанные в другую область памяти потоком, который выполнил освобождение (release), становятся видимыми в данном потоке.
memory_order_release Операция сохранения с этим упорядочением памяти выполняет операцию освобождения (release): предыдущие записи в другие области памяти, становятся видимыми для потоков, которые выполняют операцию поглощения (consume) или захвата (acquire) над той же областью памяти.
memory_order_acq_rel Операция загрузки с этим упорядочением памяти выполняет операцию захвата (acquire) над задействованной областью памяти. Операция сохранения с этим упорядочением памяти выполняет операцию освобождения (release).
memory_order_seq_cst (sequentially-consistent - последовательно согласованное) То же, что и memory_order_acq_rel, плюс существует единый общий порядок, при котором все потоки видят все изменения (см. ниже) в одинаковом порядке.

[править] Формальное описание

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

[править] Расположено-перед

(Sequenced-before)

В одном и том же потоке, вычисление A расположено-перед вычислением B, если это следует из evaluation order.

[править] Переносит-зависимость-в

(Carries-dependency-to)

В одном и том же потоке, вычисление A, которое расположено-перед вычислением B, может также переносить-зависимость-в B (то есть B зависит от A), если выполняется любое из следующих утверждений:

1) Значение A используется, как операнд B, кроме случаев
a) если B, это вызов std::kill_dependency
b) если A - это левый операнд встроенного оператора &&, ||, ?:, или ,.
2) A пишет в скалярный объект M, B читает из M
3) A переносит-зависимость-в другое вычисление X, и X переносит-зависимость-в B

[править] Порядок изменения

Все изменения любой определённой атомарной переменной происходят в общем порядке, который определён для этой атомарной переменной.

Следующие четыре требования гарантированно выполняются для всех атомарных операций:

1) Запись-запись согласованность: если вычисление A, которое изменяет некоторую атомарную M (запись) происходить-раньше вычисления B, которое изменяем M, тогда A появляется раньше, чем B в порядке изменения M.
2) Чтение-чтение согласованность: если процесс вычисления значения A некоторой атомарной M (чтение) происходит-раньше процесса вычисления значения B этой же M, и если значение A происходит из записи X в M, тогда значение B, это либо значение записанное X, либо значение записанное побочным эффектом Y, воздействующим на M, который возникает позже, чем X, в порядке изменения M.
3) Чтение-запись согласованность: если процесс вычисления значения A некоторой атомарной M (чтение) происходит-раньше операции B применяемой к M (запись), тогда значение A происходит из побочного эффекта (записи) X, который возникает раньше, чем B в порядке модификации M.
4) Запись-чтение согласованность: если побочный эффект (запись) X воздействующий на атомарный объект M происходит-раньше процесса вычисления значения (чтения) B переменной M, тогда вычисление B должно получить своё значение от X или от побочного эффекта Y, который следует за X в порядке модификации M.

[править] Последовательность освобождения

(Release sequence)

После операции освобождения (release) A, выполненной по отношению к атомарному объекту M, самая длинная непрерывная часть последовательности порядка изменения M, которая состоит из:

1) Записей выполненных тем же потоком, который выполнил A
2) Атомарных чтение-изменение-запись операций, применённых любым потоком к M

называется последовательностью освобождения во главе с A.

[править] Предшествует-по-зависимости

(Dependency-ordered before)

Межпоточно вычисление A предшествует-по-зависимости вычислению B, если выполняется любое из следующих утверждений:

1) A выполняет операцию освобождения (release) над некоторой атомарной M, и, в другом потоке, B выполняет операцию поглощения (consume) над той же атомарной M, и B читает значение, записанное любой частью последовательности освобождения во главе с A.
2) A предшестует-по-зависимости X и X переносит-зависимость-в B.

[править] Межпоточно происходит-раньше

(Inter-thread happens-before)

Вычисление A межпоточно происходит-раньше вычисления B, если выполняется любое из следующих утверждений:

1) A синхронизируется-с B
2) A предшествует-по-зависимости B
3) A синхронизируется-с некоторым вычислением X, и X расположено-перед B
4) A расположено-перед некоторым вычислением X, и X межпоточно происходит-раньше B
5) A межпоточно происходит-раньше некоторого вычисления X, и X межпоточно происходит-раньше B

[править] Происходит-раньше

(Happens-before)

В независимости от потоков, вычисление A происходит-раньше вычисления B, если выполняется любое из следующих утверждений:

1) A расположено-перед B
2) A межпоточно происходит-раньше B

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

[править] Видимые побочные эффекты

Побочный эффект A, воздействующий на скалярную M (запись) является видимым по отношению к процессу вычисления значения B переменной M (чтение), если выполняются оба следующих утверждения:

1) A происходит-раньше B
2) Никакой другой побочный эффект X, не действует на M, где A происходит-раньше X, и X происходит-раньше B

Если побочный эффект A является видимым по отношению в процессу вычисления значения B, тогда самое длинное и непрерывное подмножество побочных эффектов воздействующих на M в порядке модификации, где B не происходит-раньше, известено, как “видимая последовательность побочных эффектов” (значение M, определённое B, будет значением, сохранённым одним из этих побочных эффектов).

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

[править] Операция поглощения

(Consume operation)

Атомарная загрузка с упорядочением memory_order_consume или более строгим, является операцией поглощения (consume). Учтите, что барьер std::atomic_thread_fence не является операцией поглощения.

[править] Операция захвата

(Acquire operation)

Атомарная загрузка с упорядочением memory_order_acquire или более строгим, является операцией захвата (acquire). Операция lock(), применяемая к Mutex, также является операцией захвата. Учтите, что барьер std::atomic_thread_fence не является операцией захвата.

[править] Операция освобождения

(Release operation)

Атомарное сохранение (запись) с упорядочением memory_order_release или более строгим, является операцией освобождения (release). Операция unlock(), применяемая к Mutex, также является операцией освобождения. Учтите, что барьер std::atomic_thread_fence не является операцией освобождения.


Атомная операций отмеченных std::memory_order_relaxed обладать следующими свойствами:
Оригинал:
Atomic operations tagged std::memory_order_relaxed exhibit the following properties:
Текст был переведён автоматически через Google Translate.
Вы можете проверить и исправить перевод. Для инструкций кликните сюда.
  • Нет упорядочение других обращений к памяти обеспечивается бы то ни было. Это означает, что это не возможно для синхронизации нескольких потоков с использованием атомарных переменных.
    Оригинал:
    No ordering of other memory accesses is ensured whatsoever. This means that it is not possible to synchronize several threads using the atomic variable.
    Текст был переведён автоматически через Google Translate.
    Вы можете проверить и исправить перевод. Для инструкций кликните сюда.
  • Чтение и запись к атомной сама переменная упорядочены. Как только поток считывает значение, последующее чтение тем же потоком из того же объект не может дать ранее значение.
    Оригинал:
    Reads and writes to the atomic variable itself are ordered. Once a thread reads a value, a subsequent read by the same thread from the same object can not yield an earlier value.
    Текст был переведён автоматически через Google Translate.
    Вы можете проверить и исправить перевод. Для инструкций кликните сюда.
Например, с x и y первоначально нулю,
Оригинал:
For example, with x and y initially zero,
Текст был переведён автоматически через Google Translate.
Вы можете проверить и исправить перевод. Для инструкций кликните сюда.

// Thread 1:
r1 = y.load(memory_order_relaxed);
x.store(r1, memory_order_relaxed);
// Thread 2:
r2 = x.load(memory_order_relaxed);
y.store(42, memory_order_relaxed);

Допускается изготовление r1 == r2 == 42.
Оригинал:
is allowed to produce r1 == r2 == 42.
Текст был переведён автоматически через Google Translate.
Вы можете проверить и исправить перевод. Для инструкций кликните сюда.

[править] Релиз-Потребляйте заказа

Если атомная магазин отмеченных std::memory_order_release и атомные нагрузки от той же переменной отмеченных std::memory_order_consume, операции обладают следующими свойствами:
Оригинал:
If an atomic store is tagged std::memory_order_release and an atomic load from the same variable is tagged std::memory_order_consume, the operations exhibit the following properties:
Текст был переведён автоматически через Google Translate.
Вы можете проверить и исправить перевод. Для инструкций кликните сюда.
  • Не пишет в поток записи могут быть перераспределены после атомной магазина
    Оригинал:
    No writes in the writer thread can be reordered after the atomic store
    Текст был переведён автоматически через Google Translate.
    Вы можете проверить и исправить перевод. Для инструкций кликните сюда.
  • Не читает или пишет зависит от величины, полученной от атомного нагрузка может быть заказана до атомной нагрузки. "В зависимости от" означает, что адрес или значение вычисляется из значения атомарных переменных. Эта форма синхронизации между потоками известен как "зависимость упорядочение".
    Оригинал:
    No reads or writes dependent on the value received from atomic load can be reordered before the atomic load. "Dependent on" means that the address or value is computed from the value of the atomic variable. This form of synchronization between threads is known as "dependency ordering".
    Текст был переведён автоматически через Google Translate.
    Вы можете проверить и исправить перевод. Для инструкций кликните сюда.
  • Синхронизация установлена ​​только между потоками освобождения и' потребления той же атомной переменной. Другие темы, можно увидеть различные порядке доступа к памяти, чем один или оба синхронизированы темы.
    Оригинал:
    The synchronization is established only between the threads releasing and consuming the same atomic variable. Other threads can see different order of memory accesses than either or both of the synchronized threads.
    Текст был переведён автоматически через Google Translate.
    Вы можете проверить и исправить перевод. Для инструкций кликните сюда.
  • Синхронизация является транзитивным. То есть, если мы имеем следующую ситуацию:
    Оригинал:
    The synchronization is transitive. That is, if we have the following situation:
    Текст был переведён автоматически через Google Translate.
    Вы можете проверить и исправить перевод. Для инструкций кликните сюда.
  • Тема' выпускает атомарных переменных'.
    Оригинал:
    Thread A releases atomic variable a.
    Текст был переведён автоматически через Google Translate.
    Вы можете проверить и исправить перевод. Для инструкций кликните сюда.
  • Тема B потребляет атомарных переменных'.
    Оригинал:
    Thread B consumes atomic variable a.
    Текст был переведён автоматически через Google Translate.
    Вы можете проверить и исправить перевод. Для инструкций кликните сюда.
  • Атомная переменная B зависит от'.
    Оригинал:
    Atomic variable b is dependent on a.
    Текст был переведён автоматически через Google Translate.
    Вы можете проверить и исправить перевод. Для инструкций кликните сюда.
  • Тема B релизы атомарных переменных B.
    Оригинал:
    Thread B releases atomic variable b.
    Текст был переведён автоматически через Google Translate.
    Вы можете проверить и исправить перевод. Для инструкций кликните сюда.
  • Тема C потребляет или приобретает атомарных переменных B.
    Оригинал:
    Thread C consumes or acquires atomic variable b.
    Текст был переведён автоматически через Google Translate.
    Вы можете проверить и исправить перевод. Для инструкций кликните сюда.
Тогда не только' и B или B и C синхронизируются, но' и C тоже. То есть, все пишет в потоке A, которые были начаты до выхода' гарантированно будут завершены раз поток C отмечает в магазине B.
Оригинал:
Then not only A and B or B and C are synchronized, but A and C also. That is, all writes by the thread A that were launched before the release of a are guaranteed to be completed once thread C observes the store to b.
Текст был переведён автоматически через Google Translate.
Вы можете проверить и исправить перевод. Для инструкций кликните сюда.
На всех основных процессоров, кроме DEC Alpha, зависимость упорядочение происходит автоматически, никаких дополнительных инструкций процессора выдаются для этого режима синхронизации, только некоторые оптимизации компиляторов затронуты (например, компилятор, запрещается совершать спекулятивные нагрузки на объекты, которые участвуют в Зависимость цепи)
Оригинал:
On all mainstream CPUs, other than DEC Alpha, dependency ordering is automatic, no additional CPU instructions are issued for this synchronization mode, only certain compiler optimizations are affected (e.g. the compiler is prohibited from performing speculative loads on the objects that are involved in the dependency chain)
Текст был переведён автоматически через Google Translate.
Вы можете проверить и исправить перевод. Для инструкций кликните сюда.

[править] Отпустите последовательности

Если некоторые атомные это в магазине освобождены и некоторые другие темы, выполнять операции чтения-модификации-записи на что атомная, "освобождение последовательность" формируется: все темы, которые выполняют чтение-модификация-запись в той же атомной синхронизации с первым потоком и друг друга, даже если они не имеют memory_order_release семантики. Это делает один производитель - несколько ситуаций потребителей невозможно без введения ненужных синхронизацию между отдельными потоками потребительских.
Оригинал:
If some atomic is store-released and several other threads perform read-modify-write operations on that atomic, a "release sequence" is formed: all threads that perform the read-modify-writes to the same atomic synchronize with the first thread and each other even if they have no memory_order_release semantics. This makes single producer - multiple consumers situations possible without imposing unnecessary synchronization between individual consumer threads.
Текст был переведён автоматически через Google Translate.
Вы можете проверить и исправить перевод. Для инструкций кликните сюда.

[править] Отпустить-продам заказа

Если атомная магазин отмеченных std::memory_order_release и атомные нагрузки от той же переменной отмеченных std::memory_order_acquire, операции обладают следующими свойствами:
Оригинал:
If an atomic store is tagged std::memory_order_release and an atomic load from the same variable is tagged std::memory_order_acquire, the operations exhibit the following properties:
Текст был переведён автоматически через Google Translate.
Вы можете проверить и исправить перевод. Для инструкций кликните сюда.
  • Не пишет в поток записи могут быть перераспределены после атомной магазина
    Оригинал:
    No writes in the writer thread can be reordered after the atomic store
    Текст был переведён автоматически через Google Translate.
    Вы можете проверить и исправить перевод. Для инструкций кликните сюда.
  • Нет говорится в потоке, читатель может быть заказана до атомной нагрузки.
    Оригинал:
    No reads in the reader thread can be reordered before the atomic load.
    Текст был переведён автоматически через Google Translate.
    Вы можете проверить и исправить перевод. Для инструкций кликните сюда.
  • Синхронизация установлена ​​только между потоками освобождения и' приобретения той же атомной переменной. Другие темы, можно увидеть различные порядке доступа к памяти, чем один или оба синхронизированы темы.
    Оригинал:
    The synchronization is established only between the threads releasing and acquiring the same atomic variable. Other threads can see different order of memory accesses than either or both of the synchronized threads.
    Текст был переведён автоматически через Google Translate.
    Вы можете проверить и исправить перевод. Для инструкций кликните сюда.
  • Синхронизация является транзитивным. То есть, если мы имеем следующую ситуацию:
    Оригинал:
    The synchronization is transitive. That is, if we have the following situation:
    Текст был переведён автоматически через Google Translate.
    Вы можете проверить и исправить перевод. Для инструкций кликните сюда.
  • Тема' выпускает атомарных переменных'.
    Оригинал:
    Thread A releases atomic variable a.
    Текст был переведён автоматически через Google Translate.
    Вы можете проверить и исправить перевод. Для инструкций кликните сюда.
  • Тема B потребляет атомарных переменных'.
    Оригинал:
    Thread B consumes atomic variable a.
    Текст был переведён автоматически через Google Translate.
    Вы можете проверить и исправить перевод. Для инструкций кликните сюда.
  • Тема B релизы атомарных переменных B.
    Оригинал:
    Thread B releases atomic variable b.
    Текст был переведён автоматически через Google Translate.
    Вы можете проверить и исправить перевод. Для инструкций кликните сюда.
  • Тема C потребляет или приобретает атомарных переменных B.
    Оригинал:
    Thread C consumes or acquires atomic variable b.
    Текст был переведён автоматически через Google Translate.
    Вы можете проверить и исправить перевод. Для инструкций кликните сюда.
Тогда не только' и B или B и C синхронизируются, но' и C тоже. То есть, все пишет в потоке A, которые были начаты до выхода' гарантированно будут завершены раз поток C отмечает в магазине B.
Оригинал:
Then not only A and B or B and C are synchronized, but A and C also. That is, all writes by the thread A that were launched before the release of a are guaranteed to be completed once thread C observes the store to b.
Текст был переведён автоматически через Google Translate.
Вы можете проверить и исправить перевод. Для инструкций кликните сюда.
На строго упорядоченные системы (x86, SPARC, IBM мэйнфреймов), релиз-продам заказа является автоматическим. Никаких дополнительных инструкций процессора выдаются для этого режима синхронизации, только некоторые оптимизации компиляторов затронуты (например, компилятор запрещено выходить неатомической магазинах прошлом атомных магазине Relase или выполнять неатомической грузов раньше, чем атомная нагрузки приобрести)
Оригинал:
On strongly-ordered systems (x86, SPARC, IBM mainframe), release-acquire ordering is automatic. No additional CPU instructions are issued for this synchronization mode, only certain compiler optimizations are affected (e.g. the compiler is prohibited from moving non-atomic stores past the atomic store-relase or perform non-atomic loads earlier than the atomic load-acquire)
Текст был переведён автоматически через Google Translate.
Вы можете проверить и исправить перевод. Для инструкций кликните сюда.

[править] Последовательно-согласованных заказа

Если атомная магазин и помечен std::memory_order_seq_cst и атомные нагрузки от той же переменной отмеченных std::memory_order_seq_cst, то операции обладают следующими свойствами:
Оригинал:
If an atomic store and an is tagged std::memory_order_seq_cst and an atomic load from the same variable is tagged std::memory_order_seq_cst, then the operations exhibit the following properties:
Текст был переведён автоматически через Google Translate.
Вы можете проверить и исправить перевод. Для инструкций кликните сюда.
  • Не пишет в поток записи могут быть перераспределены после атомной магазина
    Оригинал:
    No writes in the writer thread can be reordered after the atomic store
    Текст был переведён автоматически через Google Translate.
    Вы можете проверить и исправить перевод. Для инструкций кликните сюда.
  • Нет говорится в потоке, читатель может быть заказана до атомной нагрузки.
    Оригинал:
    No reads in the reader thread can be reordered before the atomic load.
    Текст был переведён автоматически через Google Translate.
    Вы можете проверить и исправить перевод. Для инструкций кликните сюда.
  • Синхронизация между всеми членами атомарных операций отмеченных std::memory_order_seq_cst. Все темы, используя такие атомарные операции см. тот же порядок доступа к памяти.
    Оригинал:
    The synchronization is established between all atomic operations tagged std::memory_order_seq_cst. All threads using such atomic operation see the same order of memory accesses.
    Текст был переведён автоматически через Google Translate.
    Вы можете проверить и исправить перевод. Для инструкций кликните сюда.
Последовательный порядок необходимо для многих несколько производитель-потребитель несколько ситуаций, когда все потребители должны наблюдать за действиями всех производителей, входящих в том же порядке.
Оригинал:
Sequential ordering is necessary for many multiple producer-multiple consumer situations where all consumers must observe the actions of all producers occurring in the same order.
Текст был переведён автоматически через Google Translate.
Вы можете проверить и исправить перевод. Для инструкций кликните сюда.
Всего последовательное упорядочение требует полной памяти забор инструкций процессора на всех многоядерных систем. Это может стать узким местом, поскольку она заставляет всех доступ к памяти распространяться на каждую нить.
Оригинал:
Total sequential ordering requires a full memory fence CPU instruction on all multi-core systems. This may become a performance bottleneck since it forces all memory accesses to propagate to every thread.
Текст был переведён автоматически через Google Translate.
Вы можете проверить и исправить перевод. Для инструкций кликните сюда.

[править] Отношения с нестабильной

{{{1}}}
Оригинал:
{{{2}}}
Текст был переведён автоматически через Google Translate.
Вы можете проверить и исправить перевод. Для инструкций кликните сюда.

[править] Примеры

[править] std::memory_order_relaxed

В следующем примере показано задачи (обновления глобального счетчика), что требует атомарности, но нет заказов ограничений, так как неатомической памяти не участвует .
Оригинал:
The following example demonstrates a task (updating a global counter) that requires atomicity, but no ordering constraints since non-atomic memory is not involved.
Текст был переведён автоматически через Google Translate.
Вы можете проверить и исправить перевод. Для инструкций кликните сюда.

#include <vector>
#include <iostream>
#include <thread>
#include <atomic>
 
std::atomic<int> cnt = ATOMIC_VAR_INIT(0);
 
void f()
{
    for(int n = 0; n < 1000; ++n) {
        cnt.fetch_add(1, std::memory_order_relaxed);
    }
}
 
int main()
{
    std::vector<std::thread> v;
    for(int n = 0; n < 10; ++n) {
        v.emplace_back(f);
    }
    for(auto& t : v) {
        t.join();
    }
    std::cout << "Final counter value is " << cnt << '\n';
}

Вывод:

Final counter value is 10000

[править] std::memory_order_release and std::memory_order_consume

Этот пример демонстрирует зависимость заказал синхронизации: целочисленных данных не связано с указателем на строку, данные отношения зависимости, при этом его значение не определено в потребительском .
Оригинал:
This example demonstrates dependency-ordered synchronization: the integer data is not related to the pointer to string by a data-dependency relationship, thus its value is undefined in the consumer.
Текст был переведён автоматически через Google Translate.
Вы можете проверить и исправить перевод. Для инструкций кликните сюда.

#include <thread>
#include <atomic>
#include <cassert>
#include <string>
 
std::atomic<std::string*> ptr;
int data;
 
void producer()
{
    std::string* p  = new std::string("Hello");
    data = 42;
    ptr.store(p, std::memory_order_release);
}
 
void consumer()
{
    std::string* p2;
    while (!(p2 = ptr.load(std::memory_order_consume)))
        ;
    assert(*p2 == "Hello"); // never fires
    assert(data == 42); // may or may not fire
}
 
int main()
{
    std::thread t1(producer);
    std::thread t2(consumer);
    t1.join(); t2.join();
}


[править] std::memory_order_release and memory_order_acquire

Мьютексы, параллельные очереди, и другой производитель-потребитель ситуации требуют упорядочения в релизе издатель нить и приобретают упорядоченность в поток-потребитель. Эта модель устанавливает попарно синхронизации между потоками .
Оригинал:
Mutexes, concurrent queues, and other producer-consumer situations require release ordering in the publisher thread and acquire ordering in the consumer thread. This pattern establishes pairwise synchronization between threads.
Текст был переведён автоматически через Google Translate.
Вы можете проверить и исправить перевод. Для инструкций кликните сюда.

#include <thread>
#include <atomic>
#include <cassert>
#include <string>
 
std::atomic<std::string*> ptr;
int data;
 
void producer()
{
    std::string* p  = new std::string("Hello");
    data = 42;
    ptr.store(p, std::memory_order_release);
}
 
void consumer()
{
    std::string* p2;
    while (!(p2 = ptr.load(std::memory_order_acquire)))
        ;
    assert(*p2 == "Hello"); // never fires
    assert(data == 42); // never fires
}
 
int main()
{
    std::thread t1(producer);
    std::thread t2(consumer);
    t1.join(); t2.join();
}


[править] std::memory_order_acq_rel

Последующий пример демонстрирует транзитивной отпустить-продам заказе через три темы
Оригинал:
The follow example demonstrates transitive release-acquire ordering across three threads
Текст был переведён автоматически через Google Translate.
Вы можете проверить и исправить перевод. Для инструкций кликните сюда.

#include <thread>
#include <atomic>
#include <cassert>
#include <vector>
 
std::vector<int> data;
std::atomic<int> flag = ATOMIC_VAR_INIT(0);
 
void thread_1()
{
    data.push_back(42);
    flag.store(1, std::memory_order_release);
}
 
void thread_2()
{
    int expected=1;
    while (!flag.compare_exchange_strong(expected, 2, std::memory_order_acq_rel)) {
        expected = 1;
    }
}
 
void thread_3()
{
    while (flag.load(std::memory_order_acquire) < 2)
        ;
    assert(data.at(0) == 42); // will never fire
}
 
int main()
{
    std::thread a(thread_1);
    std::thread b(thread_2);
    std::thread c(thread_3);
    a.join(); b.join(); c.join();
}


[править] std::memory_order_seq_cst

Этот пример демонстрирует ситуацию, когда последовательное упорядочение необходимо. Любой другой порядок может вызвать утверждать, потому что это было бы возможно для темы c и d наблюдать изменения в Atomics x и y в обратном порядке .
Оригинал:
This example demonstrates a situation where sequential ordering is necessary. Any other ordering may trigger the assert because it would be possible for the threads c and d to observe changes to the atomics x and y in opposite order.
Текст был переведён автоматически через Google Translate.
Вы можете проверить и исправить перевод. Для инструкций кликните сюда.

#include <thread>
#include <atomic>
#include <cassert>
 
std::atomic<bool> x = ATOMIC_VAR_INIT(false);
std::atomic<bool> y = ATOMIC_VAR_INIT(false);
std::atomic<int> z = ATOMIC_VAR_INIT(0);
 
void write_x()
{
    x.store(true, std::memory_order_seq_cst);
}
 
void write_y()
{
    y.store(true, std::memory_order_seq_cst);
}
 
void read_x_then_y()
{
    while (!x.load(std::memory_order_seq_cst))
        ;
    if (y.load(std::memory_order_seq_cst)) {
        ++z;
    }
}
 
void read_y_then_x()
{
    while (!y.load(std::memory_order_seq_cst))
        ;
    if (x.load(std::memory_order_seq_cst)) {
        ++z;
    }
}
 
int main()
{
    std::thread a(write_x);
    std::thread b(write_y);
    std::thread c(read_x_then_y);
    std::thread d(read_y_then_x);
    a.join(); b.join(); c.join(); d.join();
    assert(z.load() != 0);  // will never happen
}