Всегда ли атомарные CAS-операции на x86_64 и ARM используют std :: memory_order_seq_cst?

Как Энтони Уильямс сказал:

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

4

Решение

Вам не нужно беспокоиться о том, с какими инструкциями компилятор сопоставляет данную конструкцию C11, поскольку это не все. Вместо этого вам нужно разработать код с учетом гарантий модели памяти C11. Как отмечено в приведенном выше комментарии, ваш компилятор или будущие компиляторы могут свободно изменять порядок операций с памятью, если это не нарушает модель памяти C11. Также стоит прогнать ваш код с помощью такого инструмента, как CDSChecker, чтобы увидеть, какие варианты поведения разрешены в модели памяти.

5

Другие решения

x86 гарантирует, что грузы следуют за заказами, а магазины следуют за магазинами. Учитывая, что CAS требует как загрузки, так и хранения, все операции должны быть упорядочены вокруг него.

Тем не менее, стоит отметить, что при наличии нескольких атомик с memory_order_relaxed компилятору разрешается переупорядочивать их. Это нельзя сделать с помощью memory_order_seq_cst.

1

Я думаю, что компилятор испускает lock cmpxchg даже для memory_order_relaxed потому что это единственный способ убедиться, что сравнение + обмен на самом деле атомарный. Как сказано в комментариях artless_noise, другие архитектуры могут использовать Загрузить ссылку / сохранить условно реализовать compare_exchange_weak(...),

memory_order_relaxed должен все же позволить компилятору поднимать магазины Другой переменные вне циклов, и иначе переупорядочить доступ к памяти во время компиляции.

Если бы на x86 был способ сделать это, который не был бы полным барьером памяти, хороший компилятор использовал бы его для memory_order_relaxed,

1
По вопросам рекламы [email protected]