.Net эквивалент команды x86 ASM XADD - PullRequest
1 голос
/ 27 июля 2010

Есть ли эквивалент в команде XADD в .Net?В конце концов, это наиболее эффективный метод блокировки / проверки блокировок для критических секций или для обеспечения точных приращений в многопоточной среде.

Я просмотрел коды операций IL, но не смог найти эквивалент.

Ответы [ 3 ]

7 голосов
/ 27 июля 2010

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

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

В любом случае, задачей CLR и компилятора является скрыть детали реализации.,Одним из основных классов, который делает это, является класс Monitor.Он используется, когда вы используете оператор блокировки в C #, например, компилятор автоматически преобразует его в вызов Monitor.Enter, автоматически генерируя блок try и finally, блок finally выполняет метод Leave ().

Реализация этих методов в CLR.Там есть довольно хороший кусок кода, другая вещь, которую он делает, имеет дело с "честностью".Который гарантирует, что потоки не могут голодать, пытаясь получить блокировку.Этот код написан на C ++, все еще довольно далеко от необработанных инструкций процессора.В конечном итоге это сводится к реальному коду, который реализует фактическую блокировку.Да, это написано на ассемблере, по крайней мере, в общедоступной версии CLR.Этот код находится в PAL (уровне адаптера платформы), его версия для x86 выглядит следующим образом:

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

Инструкция CPU cmpxchng с префиксом блокировки является типичной для реализации блокировок.Ваш xadd тоже покрыт, используется для Interlocked.Add:

FASTCALL_FUNC ExchangeAddUP,8
        _ASSERT_ALIGNED_4_X86 ecx
        xadd    [ecx], edx      ; Add Value to Target
        mov     eax, edx
        retn
FASTCALL_ENDFUNC ExchangeAddUP

Но это обычно не используется для блокировок.Если вы хотите убедиться в этом сами, скачайте исходный код SSCLI20 и посмотрите clr \ src \ wm \ i386 \ asmhelpers.asm.Используется ли это на самом деле в текущей версии CLR - вопрос открытый.Это довольно ядро, так что скорее всего.Реализации метода Monitor находятся в clr \ vm \ syncblk.cpp, класс AwareLock.Я почти уверен, что его версия SSCLI20 - это не то, что работает на вашей машине, они возятся с алгоритмом "справедливости".

3 голосов
/ 27 июля 2010

Ближайшим эквивалентом в .NET будет использование класса блокировки .Например, вы можете использовать Interlocked.Add для безопасного и точного приращения в многопоточной среде.

1 голос
/ 27 июля 2010

Посмотрите на класс Interlocked , уделив особое внимание Interlocked.Add. Ниже приведен пример его использования в IL.

.method private hidebysig static void Main(string[] args) cil managed
{
    .entrypoint
    .maxstack 2
    .locals init (
        [0] int32 a,
        [1] int32 b)
    L_0000: ldc.i4.5 
    L_0001: stloc.0 
    L_0002: ldc.i4.7 
    L_0003: stloc.1 
    L_0004: ldloca.s a
    L_0006: ldloc.1 
    L_0007: call int32 [mscorlib]System.Threading.Interlocked::Add(int32&, int32)
    L_000c: pop 
    L_000d: ret 
}
...