барьер памяти и atomic_t на Linux - PullRequest
12 голосов
/ 02 июля 2011

Недавно я читаю некоторые коды пространства ядра Linux, я вижу это

uint64_t used;
uint64_t blocked;

used = atomic64_read(&g_variable->used);       //#1
barrier();                                     //#2
blocked = atomic64_read(&g_variable->blocked); //#3

Какова семантика этого фрагмента кода? Убедитесь, что # 1 выполняется до # 3 на # 2. Но я немного запутался, потому что

# A На 64-битной платформе макрос atomic64_read расширяется до

used = (&g_variable->used)->counter           // where counter is volatile.

В 32-битной платформе он был преобразован для использования блокировки cmpxchg8b . Я предполагаю, что эти два имеют одинаковую семантику, и для 64-битной версии, я думаю, это означает:

  1. все или ничего , мы можем исключить случай, когда адрес не выровнен и размер слова больше, чем собственный размер слова процессора.
  2. без оптимизации , принудительное чтение CPU из области памяти.

atomic64_read не имеет семантики для сохранения порядка чтения !!! см. this

# B барьер * Макрос 1034 * определяется как

/* Optimization barrier */
/* The "volatile" is due to gcc bugs */
#define barrier() __asm__ __volatile__("": : :"memory")

Из вики это просто запрещает компилятору gcc переупорядочивать чтение и запись.

Что меня смущает, так это как отключить оптимизацию переупорядочения для процессора? Кроме того, могу ли я считать, что барьерный макрос является полным забором?

Ответы [ 2 ]

8 голосов
/ 04 июля 2011

32-битные процессоры x86 не предоставляют простых атомарных операций чтения для 64-битных типов.Единственная атомарная операция на 64-битных типах на таких процессорах, которая работает с «обычными» регистрами, - это LOCK CMPXCHG8B, поэтому она используется здесь.Альтернативой является использование MOVQ и регистров MMX / XMM, но это требует знания состояния / регистров FPU и требует, чтобы все операции над этим значением выполнялись с инструкциями MMX / XMM.

On 64-битные процессоры x86_64, выровненные чтения 64-битных типов являются атомарными и могут быть выполнены с помощью инструкции MOV, поэтому требуется только простое чтение - использование volatile просто для гарантии того, что компилятор действительновыполняет чтение и не кэширует предыдущее значение.

Что касается порядка чтения, указанный встроенный ассемблер гарантирует, что компилятор выдает инструкции в правильном порядке, и это все, что требуется дляПроцессоры x86 / x86_64 при условии правильной последовательности записи.LOCK ed записи на x86 имеют общий порядок;обычные MOV записи обеспечивают "причинную согласованность", поэтому, если поток A делает x=1, то y=2, если поток B читает y==2, то последующее чтение x приведет к x==1.

На IA-64, PowerPC, SPARC и других процессорах с более расслабленной моделью памяти вполне может быть больше atomic64_read() и barrier().

4 голосов
/ 04 июля 2011

x86 ЦП не выполняют переупорядочение «чтение после чтения», поэтому достаточно запретить компилятору переупорядочивать. На других платформах, таких как PowerPC, все будет выглядеть по-другому.

...