Что такое атомарный API C ++ 11 эквивалентен « `__asm__ volatile (& quot; & quot; ::: & quot; память & quot;)` «

Кодовая база имеет COMPILER_BARRIER макрос определяется как __asm__ volatile("" ::: "memory"), Цель макроса — не дать компилятору переупорядочить операции чтения и записи через барьер. Обратите внимание, что это явно барьер компилятора, и не барьер памяти на уровне процессора.

Как это, это довольно переносимо, так как в AssemblerTemplate нет реальных инструкций по сборке, только volatile и memory тряпки. Поэтому, если компилятор учитывает синтаксис GCC Extended Asm, он должен работать нормально. Тем не менее, мне любопытно, как правильно выразить это в атомарном API C ++ 11, если это возможно.

Казалось, что это может быть правильной идеей: atomic_signal_fence(memory_order_acq_rel);,

Мои рассуждения таковы:

  • Из <atomic> Только API atomic_signal_fence а также atomic_thread_fence не требуется адрес памяти, по которому можно работать.
  • atomic_thread_fence влияет на порядок памяти, который нам не нужен для барьера компилятора.
  • memory Clobber в расширенной версии Asm не различает чтение и запись, поэтому кажется, что мы хотим получить и выпустить семантику, поэтому memory_order_acq_rel кажется, требуется, как минимум.
  • memory_order_seq_cst кажется ненужным, поскольку нам не требуется общий порядок между потоками — нас интересует только последовательность команд в текущем потоке.

Можно ли выразить эквивалент __asm__ volatile("" ::: "memory") полностью переносимо с помощью атомарного API C ++ 11? Если это так, atomic_signal_fence правильный API для использования? Если да, то какой аргумент порядка памяти здесь уместен / необходим?

Или я здесь в сорняках, и есть лучший способ приблизиться к этому?

6

Решение

__asm__ volatile("" ::: "memory") даже не полный барьер компилятора; это только вынуждает упорядочивать загрузки / сохранения к объектам, адреса которых потенциально доступны для блока asm, который не будет включать локальные переменные, для которых компилятор может отследить, что адрес не течет. Например, memset(password, 0, len); с последующим __asm__ volatile("" ::: "memory"); может быть не в состоянии фактически обнулить память, используемую password[],

Это можно исправить, передав адреса таких объектов как входные данные в блок asm, но я не вижу идеального эквивалента с atomic_signal_fence, Самое близкое, что вы могли бы сделать, это сохранить адрес объекта во внешнем соединении. volatile объект указателя (будьте осторожны, чтобы сделать указатель, а не указатель на тип, volatileквалифицированный), а затем atomic_signal_fence придется предположить, что к нему можно получить доступ из обработчика сигнала.

3

Другие решения

Других решений пока нет …