Модель памяти TSO x86 является последовательной последовательностью + буфер хранилища, поэтому только хранилища seq-cst нуждаются в специальном ограждении. (остановка после хранилища, пока буфер хранилища не опустошится, до последующих загрузок - всенам нужно восстановить последовательную последовательность).Более слабая модель acq / rel совместима с переупорядочением StoreLoad, вызванным буфером хранилища.
(См. Обсуждение в комментариях относительно того, является ли «разрешение переупорядочения StoreLoad» точным и достаточным описанием того, что разрешает x86. Ядровсегда видит свои собственные хранилища в программном порядке, потому что загружает отслеживание буфера хранилища, так что вы могли бы сказать, что пересылка хранилища также переупорядочивает загрузки недавно сохраненных данных. За исключением того, что вы не можете всегда: Глобально невидимые инструкции загрузки )
(И, кстати, компиляторы, отличные от gcc, используют xchg
для создания хранилища seq-cst. На самом деле это больше эффективно для текущих процессоров. mov
+ mfence
GCC можетраньше они были дешевле, но в настоящее время обычно хуже, даже если вас не волнует старое значение. См. Почему хранилище std :: atomic с последовательной последовательностью использует XCHG? для сравнения между GCCmov+mfence
против xchg
. Также мой ответ на Какой лучший барьер для записи на x86: lock + addl или xchgl? )
FФакт: вы можете добиться последовательной согласованности, вместо этого ограждая seq-cst , загружает вместо хранилищ.Но в большинстве случаев дешевые грузы гораздо ценнее, чем дешевые магазины, поэтому каждый использует ABI, где в магазинах находятся полные барьеры.
См. https://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html для получения подробной информации о том, как C ++ 11атомарные операции сопоставляются с последовательностями команд asm для x86, PowerPC, ARMv7, ARMv8 и Itanium.Также Когда требуются инструкции x86 LFENCE, SFENCE и MFENCE?
, когда я использую std :: memory_order_release / acqu без оптимизации, также используется инструкция MFENCE
Это потому, что flag.store(true, std::memory_order_release);
не встроен, , потому что вы отключили оптимизацию.Это включает в себя встраивание очень простых функций-членов, таких как `` atomic :: store (T, std :: memory_order = std :: memory_order_seq_cst) `
Когда параметр упорядочения для встроенной команды __atomic_store_n()
GCC равенпеременная времени выполнения (в реализации библиотеки atomic::store()
), GCC воспроизводит ее консервативно и переводит ее в seq_cst. Это может стоить того, чтобы gcc перешагнул через mfence
, потому что это так дорого, но это не то, что мы получаем.