Я просто перечитал этот вопрос, добавив некоторые дополнительные пояснения, и понял, что предположил C11, в то время как ваш вопрос, похоже, использует встроенные компиляторы.С этой точки зрения, если все ваше memorder
использование __ATOMIC_SEQ_CST
, ни в одном случае вы не сможете наблюдать значение -1 по тем же причинам, которые я подробно описал ниже (из C11).
TL;ДР: Это зависит от обстоятельств, но вы должны были бы действительно выстрелить себе в ногу, чтобы не гарантировать такое поведение.Ниже следует объяснение того, почему это могло произойти, как это могло бы произойти, и почему вы вряд ли столкнетесь с этим.
Атомные операции гарантированноиметь глобальный порядок, но этот глобальный общий порядок не определен.Из проекта C11, §5.1.2.4p7:
Все модификации конкретного атомного объекта M происходят в некотором конкретном общем порядке, называемом порядком модификации из M .
Это определение модификаций M возможно, что общий порядок, наблюдаемый некоторым другим потоком, равен A / B, ноB / A также допускается.Это действительно приведет к тому, что внешний наблюдатель заметит, что значение изменяется между -1 и 0 (при условии, что тип атома со знаком).
Для решения этой проблемы стандарт определяет операции синхронизации (из пункта 5 того же раздела):
A операция синхронизации в одной или нескольких ячейках памяти является либо операцией получения , либо выпуском операция , либо операция получения и освобождения , либо операция потребление .
Позже, есть некоторые утомительные для чтения определенияза то, как эти операции сочетаются для введения зависимостей, которые в конечном итоге приводят к упорядочению «происходит до».Я опущу их;§5.1.2.4p14-22 описывают наблюдаемость побочных эффектов на некотором объекте и то, как на это влияют зависимости;§7.17.3 описывает API для управления этими зависимостями.
Не обсуждая эти разделы, можно надеяться, что достаточно сказать, что они позволяют наблюдателю увидеть описанный «противоположный порядок».В этой ситуации вы можете оказаться в ситуации, когда вы используете atomic_fetch_add_explicit
с аргументом memory_order_relaxed
, а ваша нагрузка реализована как atomic_load_explicit
с такими же требованиями к упорядочению памяти.В этой ситуации отношение «произойдет до» не определено, и системе разрешено разрешать потоку C наблюдать изменения в любом порядке.
Вряд ли это будет тем, что вы на самом деле делаете.С одной стороны, это намного больше печатать.Во-вторых, наименование и использование API действительно предполагает, что вы должны знать, что вы делаете, если хотите его использовать.Это то, что я имею в виду, говоря, что вам действительно нужно стрелять себе в ногу: вам не рекомендуется делать подобные вещи по умолчанию.
Если вы реализовали это чисто с atomic_fetch_add
, atomic_fetch_sub
и atomic_load
(как вы, скорее всего, сделаете), с вами все будет в порядке;стандарт в §7.17.1p5 гласит:
Функции, не заканчивающиеся на _explicit , имеют ту же семантику, что и соответствующая функция _explicit с memory_order_seq_cst для аргумента memory_order .
Стандарт гарантирует, что этот порядок будет нести зависимости данных, так что запись из потока A рассматривается как "произойдет до" записииз потока B. Поэтому наблюдателю C с его собственными последовательными требованиями к упорядочению памяти гарантируется, что операции будут чередоваться в порядке, описанном как задумано.
Это все говорит: если вы можете использовать C11, просто используйте ++
, --
и =
, и все будет в порядке.В соответствии с §6.5.16.2p3, операции +=
и -=
над атомарными типами определены так, чтобы вести себя так, как будто они используют store с memory_order_seq_cst
.Согласно §6.5.3p2 операторы ++
и --
аналогичны эквивалентным выражениям x+=1
и x-=1
.Простое назначение (§6.5.16.2) указывает, что LHS или RHS могут быть атомарными типами, но не определяет порядок памяти. Дженс Гастед говорит , что операции с _Atomic
-квалифицированными объектами гарантированно будут иметь последовательную согласованность.Я могу предугадать это только из сноски 113, а сноски не являются нормативными.Но я не думаю, что это имеет значение: если все записи согласованы, при любом чтении должно наблюдаться действительное предыдущее состояние из этого общего порядка, который никогда не содержит -1.