Место, где требуются барьеры памяти, - это когда избегает использования механизмов синхронизации ядра в среде SMP - обычно по соображениям производительности.
Существует неявный барьер памяти в любой операции синхронизации ядра (например, сигнализация семафоров, блокировка и разблокировка мутов) и переключение контента для защиты от опасностей когерентности данных.
Мне только что понадобились (умеренно) переносимые реализации барьера памяти (ARM и x86), а также я нашел, что дерево исходных текстов Linux является лучшим источником для этого. В Linux есть SMP-варианты макросов mb()
, rmb()
и wmb()
, которые на некоторых платформах приводят к более конкретным (и, возможно, менее затратным) барьерам, чем не-SMP-варианты.
Это не является проблемой для x86 и, в частности, для ARM, где оба реализованы одинаково.
Это то, что я собрал вместе из заголовочных файлов linux (подходит для ARMv7 и не древних процессоров x86 / x64)
#if defined(__i386__ ) || defined(__x64__)
#define smp_mb() asm volatile("mfence":::"memory")
#define smp_rmb() asm volatile("lfence":::"memory")
#define smp_wmb() asm volatile("sfence" ::: "memory")
#endif
#if defined(__arm__)
#define dmb() __asm__ __volatile__ ("dmb" : : : "memory")
#define smp_mb() dmb()
#define smp_rmb() dmb()
#define smp_wmb() dmb()
#endif
Естественно, что работа с барьерами памяти сопряжена с риском того, что полученный код практически невозможно протестировать, а любые возникающие ошибки будут неясными и трудными для воспроизведения условий гонки: /
Кстати, в документации по ядру Linux .
очень хорошее описание барьеров памяти.