2012-05-10 2 views
2

В своей замечательной книге «C++ параллелизм в действии» Энтони Уильямс пишет следующее (стр 309):ограничения заказные памяти на x86 архитектуре

Например, на x86 и x86-64 архитектур, операции атомное нагрузочные всегда то же самое, с меткой memory_order_relaxed или memory_order_seq_cst (см. Раздел 5.3.3). Это означает, что код, написанный с использованием упорядоченного упорядочения памяти, может работать с системами с архитектурой x86, где он потерпит неудачу в системе с более тонким набором инструкций по упорядочению памяти, таких как SPARC.

Я правильно понял, что на архитектуре x86 все операции с атомной нагрузкой - memory_order_seq_cst? Кроме того, на сайте cppreferencestd::memory_order упоминается, что на устройстве x86 выпуск-aquire-автомат.

Если это ограничение действительно, применяются ли порядковые запросы к оптимизации компилятора?

ответ

2

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

Он говорит, что на x86 у вас нет спокойного заказа, поэтому вы получаете более строгий заказ, даже если вы не просите его об этом. Это также означает, что такой код, протестированный на x86, может не работать должным образом в системе, которую делает, имеют расслабленный порядок.

5

Да, заказ по-прежнему применяется к оптимизации компилятора.

Кроме того, не совсем точно, что на x86 «операции атомной нагрузки всегда одинаковы».

На x86 все грузы, сделанные с помощью mov, приобрели семантику, и все магазины, сделанные с помощью mov, имеют семантику выпуска. Таким образом, acq_rel, acq и расслабленные нагрузки просты: mov s, и аналогично acq_rel, rel и relaxed магазины (магазины acq и rel-нагрузки всегда равны расслабленным).

Это, однако, не обязательно верно для seq_cst: архитектура не гарантия seq_cst семантика для mov. На самом деле набор инструкций x86 не имеет конкретной инструкции для последовательно согласованных нагрузок и хранилищ. Только операции атомарного чтения-изменения-записи на x86 будут иметь семантику seq_cst. Следовательно, вы можете получить семантику seq_cst для нагрузок, выполнив операцию fetch_and_add (lock xadd) с аргументом 0 и семантикой seq_cst для магазинов, выполнив операцию обмена seq_cst (xchg) и отбросив предыдущее значение.

Но вам не обязательно делать то и другое! Пока все магазины seq_cst выполняются с xchg, нагрузки seq_cst могут быть реализованы просто с помощью mov. Dually, если все нагрузки были сделаны с lock xadd, магазины seq_cst могут быть реализованы просто с помощью mov.

xchg и lock xadd намного медленнее, чем mov. Поскольку у программы (как правило) больше нагрузок, чем магазинов, удобно хранить магазины seq_cst с xchg, так что (более частые) нагрузки seq_cst могут просто использовать mov. Эта деталь реализации кодируется в бинарном интерфейсе приложений (86I).На x86 совместимый компилятор должен скомпилировать хранилища seq_cst до xchg, так что нагрузки seq_cst (которые могут отображаться в другой единицы перевода, скомпилированные с помощью другого компилятора) могут выполняться с помощью инструкции mov.

Таким образом, в общем случае это не так, что seq_cst и получение нагрузок выполняются с той же инструкцией на x86. Это верно только потому, что ABI указывает, что хранилища seq_cst скомпилированы в xchg.

0

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

0

Предложение из книги написано несколько вводящим в заблуждение способом. Порядок, полученный в архитектуре, зависит не только от того, как вы переводите атомные нагрузки, но и как вы переводите атомные магазины.

Обычный способ реализации seq_cst на x86 заключается в том, чтобы сбросить буфер хранения в какой-либо точке между любым магазином seq_cst и последующей загрузкой seq_cst из той же темы. Обычный способ для компилятора гарантировать, что это будет скрываться после магазинов, поскольку хранилища меньше, чем загрузок. В этом переводе seq_cst загрузок не нужно скрывать.

Если вы программируете x86 только с обычными грузами и магазинами, то грузы гарантируют предоставление семантики acquire, а не seq_cst.

Что касается оптимизации компилятора, то в C11/C++ 11 компилятор выполняет оптимизацию в зависимости от перемещения кода на основе семантики конкретной атомистики, прежде чем рассматривать основное оборудование. (Аппаратное обеспечение может обеспечить более сильный заказ, но из-за этого компилятор не может ограничить его оптимизацию.)