Реальный ответ: потому что модель памяти x86 уже достаточно сильна, чтобы блокировать переупорядочение во время компиляции достаточно для загрузки или упорядочения магазина; Переупорядочение во время выполнения уже заблокировано аппаратными средствами.
Это всего лишь общие c барьеры времени компиляции, сделанные через часть встроенной сборки, которая, если используется, предотвращает переупорядочение команд G CC. Это очень хорошо объяснено в этом другом посте . То, что может быть достигнуто с помощью этого «трюка», обычно также возможно с помощью спецификатора C volatile
.
Обратите внимание, что ядро Linux не использует эти указанные макросы c где-либо в коде, это всего лишь два макроса, определенные для io_uring
инструментов тестирования пользовательского пространства. Он определенно использует asm volatile ("" ::: "memory")
, где это необходимо, но под разными именами (например, smp_rmb()
, smp_wmb()
).
Модель памяти x86 делает sfence
и lfence
совершенно бесполезными для связь между процессорами; Достаточно заблокировать переупорядочение во время компиляции: см. Делает ли модель памяти Intel избыточность SFENCE и LFENCE?
smp_mb()
является полным барьером и требует фактической инструкции asm, а также блокирование переупорядочения во время компиляции.
x86 действительно имеет некоторые инструкции asm барьера памяти для барьеров памяти только для чтения и только для записи "реальной" (во время выполнения). Это sfence
(ограждение магазина), lfence
(ограждение загрузки) и mfence
(ограждение памяти = полный барьер).
mfence
сериализует чтение и запись (полный барьер), в то время как остальные только сериализовать один из двух (читает ИЛИ пишет или загружает ИЛИ сохраняет). Страница википедии , посвященная упорядочению памяти, хорошо объясняет их значение. lfence
фактически блокирует переупорядочение LoadStore, а не только LoadLoad, для слабо упорядоченных movntdqa
загрузок из памяти W C. Переупорядочение других видов загрузок из других типов памяти уже запрещено, поэтому практически никогда нет оснований использовать lfence
для упорядочения памяти вместо другого эффекта блокировки вышедшего из строя exe c.
Ядро использует те фактические инструкции asm для барьеров памяти в коде ввода / вывода, например, mb()
, rmb()
и wmb()
, которые расширяются точно до mfence
, lfence
, sfence
и другие ( пример ).
sfence
и lfence
в большинстве случаев, вероятно, излишни, например, вокруг MMIO со строго упорядоченной памятью U C. Для записи в память W C может потребоваться защита. Но они не слишком медленные по сравнению с вводом / выводом, и в некоторых случаях могут возникнуть проблемы, поэтому Linux использует безопасный подход.
В дополнение к этому, x86 имеет другой вид барьеров для чтения / записи, которые также могут быть быстрее (например, тот, который я связал выше). См. Следующие ответы для получения дополнительной информации о полных барьерах (то, что C11 называет последовательной согласованностью) с помощью либо mfence
, либо фиктивной lock
инструкции ed: