Ваш код слишком сложен. a=0
никогда не меняется, поэтому всегда читается как 0. Вы могли бы просто иметь atomic<int> b=0;
и только одну загрузку, которая просто возвращает b.load
.
Предположим, что t1закончил f1, а затем t2 только что начал f2, будет ли t2 видеть b увеличенным?
У вас нет способа обнаружить, что именно так сработало время, если вы не введете t1.join()
впереди из std::thread t2(f2);
строительства. Это потребовало бы, чтобы все в потоке 2 было упорядочено после всего в потоке 1. (Я думаю, что даже без seq_cst
забора в конце f1, но это не повредит. Я думаю, что thread.join гарантирует, что все сделано внутрипоток виден после thread.join
)
Но да, это упорядочение может произойти случайно, и тогда, конечно, это сработает.
Нет никаких гарантий, что это даже значимое условие в терминах C ++.
Но уверен, что для большинства (всех?) Реальных реализаций это то, что может произойти. И thread_fence(mo_seq_cst)
будет компилироваться в полный барьер, который блокирует этот поток, пока хранилище не зафиксирует (становится глобально видимым для всех потоков). Таким образом, выполнение не может покинуть f1, пока чтение из других потоков не увидит обновленное значение b
. (Стандарт C ++ определяет порядок и ограждения с точки зрения создания отношений «синхронизируется с», а не с точки зрения компиляции с полными барьерами, которые очищают буфер хранилища. Стандарт не упоминает буфер хранилища или переупорядочение StoreLoad или какую-либо часть памяти ЦП. порядок вещей.)
Учитывая синтетическое условие, потоки фактически упорядочены по отношению к. друг с другом, и это работает так же, как если бы все было сделано в одном потоке.
Нагрузки в diff()
не упорядочены по отношению к. друг друга, потому что они оба mo_relaxed
. Но a
никогда не модифицируется каким-либо потоком, поэтому единственный вопрос заключается в том, может ли b.load()
произойти до того, как поток даже запустится, до того, как хранилище f1
станет видимым. В реальных реализациях это невозможно из-за того, что означает «, а затем t2 только что запустил f2». Если бы он мог загрузить старое значение, то вы бы не смогли сказать «, а затем », так что это почти тавтология.
thread_fence(seq_cst)
до того, как нагрузка действительно ничего не поможет. Я думаю, это останавливает b.load()
от переупорядочения с помощью механизма запуска потока.