Я использую атомику C11 * для управления перечислением состояний между несколькими потоками. Код выглядит следующим образом:
static _Atomic State state;
void setToFoo(void)
{
atomic_store_explicit(&state, STATE_FOO, memory_order_release);
}
bool stateIsBar(void)
{
return atomic_load_explicit(&state, memory_order_acquire) == STATE_BAR;
}
Это собирает (для ARM Cortex-M4) в:
<setToFoo>:
ldr r3, [pc, #8]
dmb sy ; Memory barrier
movs r2, #0
strb r2, [r3, #0] ; store STATE_FOO
bx lr
.word 0x00000000
<stateIsBar>:
ldr r3, [pc, #16]
ldrb r0, [r3, #0] ; load state
dmb sy ; Memory barrier
sub.w r0, r0, #2 ; Comparison and return follows
clz r0, r0
lsrs r0, r0, #5
bx lr
.word 0x00000000
Почему ограждения ставятся до выпуска и после приобретения? Моя ментальная модель предполагала, что барьер будет установлен после после выпуска (для «распространения» сохраняемой переменной и всех других хранилищ на другие потоки) и до получения ( чтобы получить все предыдущие хранилища из других потоков).
* Хотя этот конкретный пример приведен в C11, ситуация идентична в C ++ 11, поскольку оба используют одни и те же концепции (и даже одни и те же перечисления), когда дело доходит до упорядочения памяти. gcc
и g++
в этой ситуации испускают один и тот же машинный код. См. http://en.cppreference.com/w/c/atomic/memory_order и http://en.cppreference.com/w/cpp/atomic/memory_order а>
stateIsBar(void)
, вы имели в видуreturn
это выражение? Потому что, как написано, это функция без оператора return, которая не возвращает void. Он должен скомпилироваться в одну инструкцию возврата (на самом деле, барьер памяти по-прежнему необходим, но не нагрузка). - person Peter Cordes   schedule 23.10.2015