Делает Взаимно блокировался. CompareExchange используют барьер памяти?

Можно найти больше информации, о котором сервисах это влияет на документах .

Microsoft

18
задан Abel 11 November 2009 в 02:04
поделиться

5 ответов

Любая инструкция x86 с префиксом lock имеет полный барьер памяти . Как показано в ответе Абеля, API-интерфейсы Interlocked * и CompareExchanges используют инструкцию с префиксом lock , такую ​​как lock cmpxchg . Итак, это подразумевает забор памяти.

Да, Interlocked.CompareExchange использует барьер памяти.

Почему? Потому что это сделали процессоры x86. Из Intel , том 3A: Руководство по системному программированию, часть 1 , раздел 7.1.2.2:

Для процессоров семейства P6 заблокированные операции сериализуют все невыполненные операции загрузки и сохранения (то есть дождитесь их завершения). Это правило также справедливо для процессоров Pentium 4 и Intel Xeon, за одним исключением. Операции загрузки, которые ссылаются на слабо упорядоченные типы памяти (такие как тип памяти WC), не могут быть сериализованы.

volatile не имеет ничего общего с этим обсуждением. Речь идет об атомарных операциях; для поддержки атомарных операций в ЦП x86 гарантирует выполнение всех предыдущих загрузок и сохранений.

23
ответ дан 21 October 2019 в 05:29
поделиться

ref не соблюдает обычные правила volatile , особенно в таких случаях, как:

volatile bool myField;
...
RunMethod(ref myField);
...
void RunMethod(ref bool isDone) {
    while(!isDone) {} // silly example
}

Здесь RunMethod не гарантирует выявить внешние изменения в isDone , даже если базовое поле ( myField ) является изменчивым ; RunMethod не знает об этом, поэтому у него неправильный код.

Однако! Это не должно вызывать проблем:

  • если вы используете Interlocked , тогда используйте Interlocked для всего доступа к полю
  • , если вы используя блокировку , затем используйте блокировку для весь доступ к полю

Следуйте этим правилам, и все должно работать нормально.


Повторное редактирование; да, что поведение является важной частью Interlocked . Честно говоря, я не знаю, как это реализовано (барьер памяти и т. Д. - обратите внимание, что это методы "InternalCall", поэтому я не могу проверить ;-p) - но да: обновления из одного потока будут немедленно видны для все остальные , пока используют методы Interlocked (отсюда и моя точка зрения выше).

10
ответ дан 21 October 2019 в 05:29
поделиться

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

Поскольку вы передаете ссылку на функцию C #, базовый код ассемблера будет работать с адрес фактического целого числа, поэтому доступ к переменной не будет оптимизирован. Он будет работать именно так, как ожидалось.

edit: Вот ссылка, которая лучше объясняет поведение инструкции asm: http://faydoc.tripod.com/cpu/cmpxchg.htm
Как вы можете видеть , шина останавливается из-за принудительного цикла записи, поэтому любые другие «потоки» (читай: другие ядра процессора), которые попытаются использовать шину одновременно, будут помещены в очередь ожидания.

2
ответ дан 21 October 2019 в 05:29
поделиться

MSDN говорит о функциях Win32 API: « Большинство взаимосвязанных функций обеспечивают полные барьеры памяти на всех платформах Windows »

(исключение составляют функции Interlocked с явной семантикой Acquire / Release)

Из этого я могу сделать вывод, что среда выполнения C # заблокирована дает те же гарантии, поскольку они задокументированы с идентичным во всем остальном поведением (и они разрешаются к внутренним операторам ЦП на платформах, которые я знаю). К сожалению, из-за тенденции MSDN размещать образцы вместо документации, это явно не прописано.

2
ответ дан 21 October 2019 в 05:29
поделиться

Кажется, есть некоторое сравнение с одноименными функциями Win32 API, но этот поток посвящен классу C # Interlocked . Из самого его описания гарантируется, что его операции атомарны. Я не уверен, как это означает «полные барьеры памяти», как упоминалось в других ответах здесь, но судите сами.

В однопроцессорных системах ничего особенного не происходит, есть только одна инструкция:

FASTCALL_FUNC CompareExchangeUP,12
        _ASSERT_ALIGNED_4_X86 ecx
        mov     eax, [esp+4]    ; Comparand
        cmpxchg [ecx], edx
        retn    4               ; result in EAX
FASTCALL_ENDFUNC CompareExchangeUP

Но в многопроцессорных системах аппаратная блокировка используется для предотвращения одновременного доступа к данным другим ядрам:

FASTCALL_FUNC CompareExchangeMP,12
        _ASSERT_ALIGNED_4_X86 ecx
        mov     eax, [esp+4]    ; Comparand
  lock  cmpxchg [ecx], edx
        retn    4               ; result in EAX
FASTCALL_ENDFUNC CompareExchangeMP

Интересное чтение с кое-где есть некоторые неправильные выводы, но в целом это сообщение блога на CompareExchange превосходно по этой теме.

6
ответ дан 21 October 2019 в 05:29
поделиться
Другие вопросы по тегам:

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