Я столкнулся с этой эмиссией кода для x64, где «Atomic Load» использует простой movq
, тогда как «Atomic Store» использует xchgq
.
Эта ссылка объясняет, что атомарная загрузка/хранилища на выровненных адресах по умолчанию являются атомарными. Я предполагаю, что именно поэтому Atomic Load в приведенной выше ссылке использует простой movq.
У меня есть следующие вопросы;
Использует ли Atomic Store xchgq
(который по умолчанию включает LOCK) для устранения проблем со строками кеша? по сути, он следит за тем, чтобы все строки кэша обновлялись правильно? Если бы строка кэша не была проблемой, они могли бы просто использовать movq?
Означает ли это также, что когерентность кеша является проблемой только при хранении? Поскольку загрузка выше не использует заблокированную инструкцию?
Нет, магазины seq_cst используют xchg
(или mov
+ mfence
, но это медленнее на последних процессорах) для заказа wrt. другие операции. release
или relaxed
атомарные хранилища могут просто использовать mov
и по-прежнему будут быстро видны другим ядрам. (Однако не раньше, чем могут быть выполнены более поздние загрузки в этом потоке.)
Когерентность кэша не является причиной переупорядочения памяти, это локально для каждого ядра. (Для x86 модель памяти представляет собой порядок программы + буфер сохранения с пересылкой сохранения. Это буфер сохранения, который заставляет хранилища не становиться видимыми до тех пор, пока инструкция сохранения не будет удалена из неупорядоченного выполнения.)
Ответ , который вы связали , в котором говорится: «Если я установлю для этого значение true (или false), ни один другой поток не будет читать другое значение после того, как я его установил» (это не совсем такая уверенность - вам нужна «блокировка» префикс, чтобы гарантировать это). несколько вводит в заблуждение. Они означают, что (неявная блокировка) xchg
включает в себя полный барьер памяти, поэтому ни один код в потоке хранения не может получить доступ к памяти до тех пор, пока хранилище не будет фактически зафиксировано в кеше, глобально видимом.
Более ясный способ заявить, что это заставляет этот поток ждать, ничего не делая, пока хранилище не станет видимым. т. е. приостановить этот поток до тех пор, пока буфер хранилища не завершит фиксацию всех предыдущих хранилищ. В конечном итоге это произойдет само по себе. Так что на самом деле речь идет об упорядочении этого потока относительно видимости хранилища, а не других потоков. Другие потоки (ядра) могут локально выполнять раннюю загрузку/позднее сохранение, хотя на x86 все загрузки происходят в порядке программы. Вот почему я прокомментировал этот ответ, на который вы ссылались, чтобы не согласиться с тем, как он представлял вещи.
volatile
, которая похожа на C++ std::atomic
с memory_order_seq_cst
.@Dan: Да, только для магазинов seq_cst. (Для стандартного способа восстановления последовательной согласованности поверх модели памяти x86; другим способом будет полный барьер перед каждой загрузкой SC, но дешевые загрузки и дорогие хранилища seq-cst намного лучше. Вот почему компиляторы / ABI не делайте этого. cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html). foo.store(1, memory_order_release)
требуется только mov
, поэтому предпочитайте это, если вам действительно не нужен seq_cst; это намного дешевле для производительности окружающего кода на большинстве ISA.
Большое спасибо. Так что все дело в упорядочении памяти и не имеет ничего общего с когерентностью кеша. Загрузки x86 по умолчанию согласованы по последовательностям, поэтому префиксы LOCK не нужны. Однако хранилищам нужна блокировка, чтобы сделать их последовательно согласованными.