Вот четыре подхода, чтобы сделать последовательную согласованность в x86/x86_64:
- LOAD (без забора) и STORE + MFENCE
- LOAD (без забора) и LOCK XCHG
- MFENCE + LOAD and STORE (без забора)
- LOCK XADD (0) и STORE (без забора)
Как написано здесь: http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html
C/С++ 11 Операция x86
- Загрузка Seq_Cst: MOV (из памяти)
- Сохранить Seq Cst: (LOCK) XCHG// альтернатива: MOV (в память), MFENCE
Примечание: существует альтернативное отображение C/С++ 11 на x86, которое вместо блокировки (или ограждения) хранилище Seq Cst блокирует/ограждает загрузку Seq Cst:
- Загрузка Seq_Cst: LOCK XADD (0)//альтернатива: MFENCE, MOV (из памяти)
- Сохранить Seq Cst: MOV (в память)
GCC 4.8.2 (GDB в x86_64) использует первый (1) подход для С++ 11-std:: memory_order_seq_cst, т.е. LOAD (без забора) и STORE + MFENCE:
std::atomic<int> a;
int temp = 0;
a.store(temp, std::memory_order_seq_cst);
0x4613e8 <+0x0058> mov 0x38(%rsp),%eax
0x4613ec <+0x005c> mov %eax,0x20(%rsp)
0x4613f0 <+0x0060> mfence
Как мы знаем, это MFENCE = LFENCE + SFENCE. Тогда этот код мы можем переписать на это: LOAD(without fence) and STORE+LFENCE+SFENCE
Вопросы:
- Почему нам не нужно использовать LFENCE здесь до LOAD, и вам нужно использовать LFENCE после STORE (потому что LFENCE имеет смысл только до LOAD!)?
- Почему GCC не использует подход: LOAD (без забора) и STORE + SFENCE для std:: memory_order_seq_cst?