Всегда ли одна инструкция на ассемблере выполняется атомарно?

$dom = new DOMDocument;
$dom->loadXML($xml);
$dom->getElementsByTagName('root')->item(0)
   ->removeChild($dom->getElementsByTagName('remove')->item(0));

Это очень специфично. Вы можете использовать XPath, если вам нужна общая общность:

foreach ($xpath->query('//remove') as $node) {
   $node->parentNode->removeChild($node);
}
13
задан starblue 14 November 2009 в 09:32
поделиться

10 ответов

Конкретно для x86 и в отношении вашего примера: counter ++ , есть несколько способов его компиляции. Самый тривиальный пример:

inc counter

Это переводится в следующие микрооперации:

  • загрузить счетчик в скрытый регистр на ЦП
  • увеличить регистр
  • сохранить обновленный регистр в counter

Это по сути то же самое, что:

mov eax, counter
inc eax
mov counter, eax

Обратите внимание, что если какой-либо другой агент обновит счетчик между загрузкой и хранилищем, он выиграет ' t отражается в счетчике после накопления. Этот агент может быть другим потоком в том же ядре, другим ядром в том же процессоре, другим процессором в той же системе или даже каким-то внешним агентом, который использует DMA (прямой доступ к памяти).

Если вы хотите гарантировать, что это inc является атомарным, используйте префикс lock :

lock inc counter

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


Что касается более сложные инструкции, вы обычно не можете предположить, что они будут выполняться атомарно, если они не поддерживают префикс lock .

19
ответ дан 1 December 2019 в 17:55
поделиться

Ответ: это зависит!

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

Тем не менее, вопрос сводится к тому, что одна машинная инструкция атомарна?

В старые добрые времена так и было. Но сегодня со сложными процессорами, длительными инструкциями, гиперпоточностью ... это не так. Некоторые процессоры гарантируют, что некоторые инструкции увеличения / уменьшения являются атомарными. Причина в том, что они удобны для очень простой синхронизации.

Также некоторые команды ЦП не так проблемны. Когда у вас есть простая выборка (одного фрагмента данных, который процессор может получить одним фрагментом) - сама выборка, конечно, атомарна, потому что делить нечего. Но когда у вас есть невыровненные данные, все снова становится сложным.

Ответ: это зависит от обстоятельств. Внимательно прочтите инструкцию производителя по эксплуатации машины. Сомневаюсь, что это не так!

Редактировать: Ой, я сейчас это видел, вы тоже просите счетчик ++. Высказыванию «скорее всего, будет переведено» вообще нельзя верить. Конечно, это во многом зависит и от компилятора! Это становится труднее, когда компилятор выполняет различные оптимизации.

7
ответ дан 1 December 2019 в 17:55
поделиться

Возможно, это не настоящий ответ на ваш вопрос, но (при условии, что это C # или другой язык .NET), если вы хотите, чтобы counter ++ действительно был многопоточным атомарным , вы можете использовать System.Threading.Interlocked.Increment (counter) .

См. другие ответы для получения актуальной информации о множестве различных способов, почему / как counter ++ не может быть атомарным. ; -)

1
ответ дан 1 December 2019 в 17:55
поделиться

На многих других процессорах разделение между системой памяти и процессором больше. (часто этот процессор может быть малым или прямым в зависимости от системы памяти, такой как ARM и PowerPC), это также имеет последствия для атомарного поведения, если система памяти может переупорядочивать операции чтения и записи.

Для этого существуют барьеры памяти ( http://en.wikipedia.org/wiki/Memory_barrier )

Короче говоря, в то время как атомарные инструкции достаточно на Intel (с соответствующими префиксы блокировки), необходимо сделать больше для не-Intel, так как операции ввода-вывода памяти могут быть в другом порядке.

Это известная проблема при переносе решений без блокировки с Intel на другие архитектуры.

​​(Обратите внимание, что многопроцессорные (не многоядерные) системы на x86, похоже, также нуждаются в барьерах памяти, по крайней мере, в 64-битном режиме.

-1
ответ дан 1 December 2019 в 17:55
поделиться

Нет, вы не можете этого предположить. Если это четко не указано в спецификации компилятора. Более того, никто не может гарантировать, что одна-единственная инструкция ассемблера действительно атомарна. На практике каждая инструкция ассемблера транслируется в число операций микрокода - упс.
Также проблема состояния гонки тесно связана с моделью памяти (согласованность, последовательность, согласованность выпуска и т. Д.), Для каждой из них ответ и результат могут быть разными.

3
ответ дан 1 December 2019 в 17:55
поделиться

Аннулировано комментарием Натана: Если я правильно помню свой ассемблер Intel x86, инструкция INC работает только с регистрами и не работает напрямую с ячейками памяти.

Таким образом, счетчик ++ не будет отдельной инструкцией в ассемблере (просто игнорируя часть постинкремента. ). Это будет как минимум три инструкции: загрузить переменную счетчика в регистр, увеличить регистр, загрузить регистр обратно в счетчик. И это только для архитектуры x86.

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

4
ответ дан 1 December 2019 в 17:55
поделиться

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

2
ответ дан 1 December 2019 в 17:55
поделиться

Я думаю, что вы получите состояние гонки при доступе.

Если вы хотите обеспечить атомарную операцию при увеличении счетчика, вам нужно будет использовать ++ counter.

]
-3
ответ дан 1 December 2019 в 17:55
поделиться

Не всегда - на некоторых архитектурах одна инструкция сборки транслируется в одну инструкцию машинного кода, а на других - нет.

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

Вместо этого используйте правильные методы синхронизации, в зависимости от языка, на котором вы кодируете.

7
ответ дан 1 December 2019 в 17:55
поделиться
  1. Операции увеличения / уменьшения 32-разрядных или менее целочисленных переменных на одном 32-разрядном процессоре без технологии Hyper-Threading являются атомарными.
  2. На процессоре с технологией Hyper-Threading или в многопроцессорной системе приращение Операции / декремент НЕ гарантированно будут выполняться автоматически.
5
ответ дан 1 December 2019 в 17:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: