Эффект, который вы пытаетесь создать, не зависит от порядка исполнения .Это только одна из вещей, которая может изменить порядок памяти.Кроме того, современный x86 выполняет неупорядоченное выполнение, но использует свой буфер порядка памяти, чтобы гарантировать, что хранилища фиксируют L1d / становятся глобально видимыми в программном порядке.(Поскольку модель памяти x86 допускает только переупорядочение StoreLoad, но не StoreStore.)
Переупорядочение памяти отделено от перестановки команд выполнение , потому что даже процессоры обычного порядка используют буфер хранилища, чтобы избежать остановкиcache-miss store.
Выполнение команды вне порядка: сохраняется ли порядок фиксации?
Является ли загрузка и сохранение единственной инструкцией, которая переупорядочивается?
Реализация AC на процессоре ARM в порядке могла бы печатать 11 или 33, если бы x
и f
оказались в разных строках кэша.
Я предполагаю, что вы скомпилировали с отключенной оптимизацией, поэтому ваш компилятор эффективно обрабатывает все ваши переменные volatile
, то есть volatile int x,f
.В противном случае цикл while(f==0);
скомпилируется в if(f==0) { infloop; }
, проверяя только f
один раз.(Гонка данных UB для неатомарных переменных - это то, что позволяет компиляторам поднимать нагрузки из циклов, но volatile
нагрузки должны выполняться всегда. https://electronics.stackexchange.com/questions/387181/mcu-programming-c-o2-optimization-breaks-while-loop#387478).
Запасы в результирующем асм / машинном коде будутпоявляются в исходном порядке C.
Вы компилируете для x86, который имеет сильную модель памяти: хранилища x86 - хранилища релизов, а нагрузки x86 - загрузочные нагрузки .получить последовательную согласованность, но вы получите acq_rel бесплатно. (И с неоптимизированным кодом это происходит, даже если вы не просите об этом.)
Таким образом, при компиляции без оптимизации для x86 ваша программаэквивалентно
_Atomic int x, f;
int main(){
...
pthread_create
atomic_store_explicit(&x, 33, memory_order_release);
atomic_store_explicit(&f, 1, memory_order_release);
...
}
и аналогично для стороны загрузки. while(f==0){}
- это нагрузочная загрузка на x86, поэтому сторона чтения ожидает, пока не увидит ненулевое значение f
, что также гарантируетвидит x==33
.
Но если вы скомпилировали для слабо упорядоченного ISA, такого как ARM или PowerPC, то порядок упорядочения памяти на уровне ассемблера позволяет переупорядочивать StoreStore и LoadLoad, так что это будет возможно для вашего pr.ogram для печати 11
, если компилируется без оптимизации.
См. также https://preshing.com/20120930/weak-vs-strong-memory-models/