some_atomic.load (std :: memory_order_acquire) просто заходит в
простая инструкция по загрузке и
some_atomic.store (std :: memory_order_release) переходит к простой
Хранить инструкцию.
Известно, что на x86 для операций load()
а также store()
барьеры памяти memory_order_consume, memory_order_acquire, memory_order_release, memory_order_acq_rel
не требует инструкций процессора.
Но на ARMv8 мы знаем, что здесь есть барьеры памяти как для load()
а также store()
:
http://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Herb-Sutter-atomic-Weapons-1-of-2
http://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Herb-Sutter-atomic-Weapons-2-of-2
О разных архитектурах процессоров: http://g.oswego.edu/dl/jmm/cookbook.html
Далее, но для CAS-операции на x86, эти две строки с разными барьерами памяти идентичны в коде разборки (MSVS2012 x86_64):
a.compare_exchange_weak(temp, 4, std::memory_order_seq_cst, std::memory_order_seq_cst);
000000013FE71A2D mov ebx,dword ptr [temp]
000000013FE71A31 mov eax,ebx
000000013FE71A33 mov ecx,4
000000013FE71A38 lock cmpxchg dword ptr [temp],ecx
a.compare_exchange_weak(temp, 5, std::memory_order_relaxed, std::memory_order_relaxed);
000000013FE71A4D mov ecx,5
000000013FE71A52 mov eax,ebx
000000013FE71A54 lock cmpxchg dword ptr [temp],ecx
Код разборки, скомпилированный GCC 4.8.1 x86_64 — GDB:
a.compare_exchange_weak(temp, 4, std::memory_order_seq_cst, std::memory_order_seq_cst);
a.compare_exchange_weak(temp, 5, std::memory_order_relaxed, std::memory_order_relaxed);
0x4613b7 <+0x0027> mov 0x2c(%rsp),%eax
0x4613bb <+0x002b> mov $0x4,%edx
0x4613c0 <+0x0030> lock cmpxchg %edx,0x20(%rsp)
0x4613c6 <+0x0036> mov %eax,0x2c(%rsp)
0x4613ca <+0x003a> lock cmpxchg %edx,0x20(%rsp)
На платформе x86 / x86_64 для любых атомарных CAS-операций, например, такой atomic_val.compare_exchange_weak(temp, 1, std::memory_order_relaxed, std::memory_order_relaxed);
всегда доволен заказом std::memory_order_seq_cst
?
И если любая операция CAS на x86 всегда выполняется с последовательной согласованностью (std::memory_order_seq_cst
) независимо от барьеров, то на ARMv8 это одинаково?
ВОПРОС: Если порядок std::memory_order_relaxed
за CAS
заблокировать шину памяти на х86 или ARM?
ОТВЕТ: На х86 любой compare_exchange_weak()
операции с любым std::memory_orders
(четное std::memory_order_relaxed
) всегда переводится на LOCK CMPXCHG
с замком автобуса, чтобы быть действительно атомным, и имеют одинаково дорого XCHG
— « cmpxchg
так же дорого, как и xchg
инструкция».
(Дополнение: XCHG
равно LOCK XCHG
, но CMPXCHG
не равно LOCK CMPXCHG
(что действительно атомно)
На ARM и PowerPC для любого `compare_exchange_weak () для разных std :: memory_orders там инструкции процессора дифференцированных замков, через LL / SC.
Процессор памяти-барьеры-инструкции для x86 (кроме CAS), ARM и PowerPC: http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html
Вам не нужно беспокоиться о том, с какими инструкциями компилятор сопоставляет данную конструкцию C11, поскольку это не все. Вместо этого вам нужно разработать код с учетом гарантий модели памяти C11. Как отмечено в приведенном выше комментарии, ваш компилятор или будущие компиляторы могут свободно изменять порядок операций с памятью, если это не нарушает модель памяти C11. Также стоит прогнать ваш код с помощью такого инструмента, как CDSChecker, чтобы увидеть, какие варианты поведения разрешены в модели памяти.
x86 гарантирует, что грузы следуют за заказами, а магазины следуют за магазинами. Учитывая, что CAS требует как загрузки, так и хранения, все операции должны быть упорядочены вокруг него.
Тем не менее, стоит отметить, что при наличии нескольких атомик с memory_order_relaxed компилятору разрешается переупорядочивать их. Это нельзя сделать с помощью memory_order_seq_cst.
Я думаю, что компилятор испускает lock cmpxchg
даже для memory_order_relaxed
потому что это единственный способ убедиться, что сравнение + обмен на самом деле атомарный. Как сказано в комментариях artless_noise, другие архитектуры могут использовать Загрузить ссылку / сохранить условно реализовать compare_exchange_weak(...)
,
memory_order_relaxed
должен все же позволить компилятору поднимать магазины Другой переменные вне циклов, и иначе переупорядочить доступ к памяти во время компиляции.
Если бы на x86 был способ сделать это, который не был бы полным барьером памяти, хороший компилятор использовал бы его для memory_order_relaxed
,