Является ли x86 CMPXCHG атомарным?
документация intel на
говорит
" эта инструкция может использоваться с префиксом блокировки, чтобы инструкция могла выполняться атомарно."
У меня вопрос
может ли CMPXCHG работать с адресом памяти? Из документа кажется, нет, но может ли кто-нибудь подтвердить, что работает только с фактическим значением в регистрах, а не с адресом памяти?
Если CMPXCHG не является атомарным и CAS уровня языка высокого уровня должен быть реализован через блокировку CMPXCHG (с префиксом блокировки), какова цель введения такой инструкции вообще?
3 ответов
вы смешиваете блокировки высокого уровня с функцией низкоуровневого процессора, которая была названа LOCK
.
высокоуровневые блокировки, которых пытаются избежать алгоритмы без блокировки, могут защищать произвольные фрагменты кода, выполнение которых может занять произвольное время, и, таким образом, эти блокировки должны будут помещать потоки в состояние ожидания, пока блокировка не будет доступна, что является дорогостоящей операцией, например, подразумевает поддержание очереди ожидающих потоков.
это совершенно другая вещь, чем CPU LOCK
функция префикса, которая защищает только одну инструкцию и, таким образом, может содержать другие потоки в течение только этой одной инструкции. Поскольку это реализовано самим процессором, это не требует дополнительных программных усилий.
поэтому задача разработки алгоритмов без блокировки заключается не в полном удалении синхронизации, она сводится к уменьшению критического раздела кода до одной атомной операции, которая будет обеспечиваться процессором себя.
похоже, что часть того, что вы действительно спрашиваете:
почему
lock
префикс неявные дляcmpxchg
С операндом памяти, какxchg
?
простой ответ (который дали другие) заключается в том, что Intel разработала его таким образом. Но это приводит к вопросу:
почему Intel это сделала? Есть ли прецедент для
cmpxchg
безlock
?
в системе с одним процессором,cmpxchg
is atomic по отношению к другим потокам или любому другому коду, работающему на том же ядре процессора. (Но не для" системных " наблюдателей, таких как устройство ввода-вывода с отображением памяти или устройство, выполняющее чтение DMA нормальной памяти, поэтому lock cmpxchg
было актуально даже на uniprocessor CPU designs).
переключатели контекста могут происходить только при прерываниях, а прерывания происходят до или после инструкции, не в середине. Любой код, запущенный на том же процессоре, увидит cmpxchg
как полностью выполненный или вообще не.
например, ядро Linux обычно компилируется с поддержкой SMP, поэтому оно использует lock cmpxchg
для atomic CAS. Но при загрузке на однопроцессорной системе он будет исправлять lock
префикс к nop
везде этот код был встроен, начиная с nop
cmpxchg
работает намного быстрее, чем lock cmpxchg
. Для получения дополнительной информации см. Это LWN статья о Система "SMP alternatives" Linux. Он даже может вернуться к lock
префиксы перед горячим подключением второго процессора.
подробнее об атомарности единичных инструкций в однопроцессорных системах в ответ и @supercat это на num++
атомарным для int num
. См.мой ответ тут для множества деталей о том, как атомарность действительно работает / реализуется для инструкций чтения-изменения-записи, таких как lock cmpxchg
.
(это же рассуждение относится и к cmpxchg8b
/ cmpxchg16b
и xadd
, который обычно используется только для synchonization / atomic ops, а не для ускорения работы однопоточного кода. Очевидно, память-назначение add [mem], reg
полезно за пределами lock add [mem], reg
случае.)
префикс блокировки предназначен для блокировки доступа к памяти для текущей команды, чтобы другие команды, находящиеся в конвейере ЦП, могли получить доступ к памяти в это время. Используя префикс блокировки, выполнение команды не будет прерываться другой командой в конвейере ЦП из-за доступа к памяти других команд, выполняемых одновременно. В руководстве INTEL говорится:
префикс блокировки может быть добавлен только к следующему в структурах и только тем формы инструкций, где пункт назначения операнд-это операнд памяти: ADD, ADC, AND, BTC, BTR, BTS, CMPXCHG, CMPXCH8B, инструкции cmpxchg16b, дек, ИНК, нег, не, или, СББ, суб, исключающее ИЛИ, XADD, и XCHG. Если префикс блокировки используется с одной из этих инструкций и исходный операнд-это операнд памяти, неопределенное исключение кода операции (#UD) может быть сгенерирован.