Рассмотрим
std::atomic<int> x(0);
Предположим, у меня есть функция, выполняющая следующее:
int x_old = x.fetch_add(1,std::memory_order_acq_rel);
На основе описание для упорядочения памяти:
memory_order_relaxed Расслабленная операция: нет никаких ограничений синхронизации или упорядочения, требуется только атомарность этой операции (см. Расслабленное упорядочение ниже)
memory_order_consume Операция загрузки с этим порядком памяти выполняет операцию потребления в уязвимом месте памяти: никакие операции чтения или записи в текущем потоке в зависимости от загруженного в данный момент значения не могут быть переупорядочены перед этой загрузкой. Запись в зависимые от данных переменные в других потоках, которые выпускают ту же атомарную переменную, видна в текущем потоке. На большинстве платформ это влияет только на оптимизацию компилятора (см. Порядок выпуска-потребления ниже)
memory_order_acquire Операция загрузки с этим порядком памяти выполняет операцию получения в уязвимом месте памяти: никакие операции чтения или записи в текущем потоке не могут быть переупорядочены до этой загрузки. Все записи в других потоках, которые выпускают одну и ту же атомарную переменную, видны в текущем потоке (см. Порядок выпуска-получения ниже)
memory_order_release Операция сохранения с этим порядком памяти выполняет операцию освобождения: после этого сохранения никакие операции чтения или записи в текущем потоке не могут быть переупорядочены. Все записи в текущем потоке видны в других потоках, которые получают одну и ту же атомарную переменную (см. Порядок упорядочения Release-Acquire ниже), и записи, которые переносят зависимость в атомарную переменную, становятся видимыми в других потоках, которые используют тот же атомарный (см. Release-Consume). порядок ниже).
memory_order_acq_rel Операция чтения-изменения-записи с этим порядком памяти является и операцией получения, и операцией освобождения. Никакие операции чтения или записи в памяти в текущем потоке не могут быть переупорядочены ни до, ни после этого хранилища. Все записи в других потоках, которые выпускают одну и ту же атомарную переменную, видны до модификации, а модификация видна в других потоках, которые получают ту же атомарную переменную.
memory_order_seq_cst Любая операция с этим порядком памяти является и операцией получения, и операцией освобождения, плюс существует единый общий порядок, в котором все потоки наблюдают все модификации в одном и том же порядке (см. Последовательно-последовательный порядок ниже)
Возможно ли для двух разных потоков получать одинаковые x_old
значение 0? Или они гарантированно выполнятся таким образом, чтобы x_old
0 для только одного из них и 1 для другого.
Если это правда, что x_old
может быть 0 для них обоих, делает изменение порядка памяти в std::memory_order_seq_cst
гарантировать уникальность x_old
?
Возможно ли для двух разных потоков получить одинаковое значение x_old, равное 0?
Это невозможно, потому что операция атомное. Это или происходит полностью, или не происходит вообще.
Заказ касается предшествующих / следующих грузов / магазинов, и так как у вас их нет, заказ здесь не имеет значения. Другими словами, x.fetch_add(1, std::memory_order_relaxed);
имеет такой же эффект здесь.
На нынешнем x86 это то же самое lock xadd
инструкция независимо от memory_order
, lock
Префикс обеспечивает как атомарность, так и порядок. За memory_order_relaxed
упорядочивающая часть lock
не нужно
Других решений пока нет …