Написав ответ на еще один вопрос, появилось несколько интересных вещей, и теперь я не понимаю, как Interlocked.Increment(ref long value)
работает на 32-битных системах. Позвольте мне объяснить.
Нативный InterlockedIncrement64
теперь недоступен при компиляции для 32-разрядной среды, это имеет смысл, потому что в .NET вы не можете выровнять память по мере необходимости, и ее можно вызвать из управляемой, а затем она ее удалила.
В .NET мы можем вызвать Interlocked.Increment()
со ссылкой на 64-битную переменную, у нас все еще нет ограничений относительно ее выравнивания (например, в структуре, где мы можем использовать FieldOffset
и StructLayout
), но в документации не упоминается никаких ограничений (AFAIK). Это волшебство, это работает!
Hans Passant отметил, что Interlocked.Increment()
- это специальный метод, распознаваемый JIT-компилятором, и он выдает вызов COMInterlocked:: ExchangeAdd64() который затем вызывается FastInterlockExchangeAddLong, который является макросом для InterlockedExchangeAdd64, который разделяет те же ограничения InterlockedIncrement64.
Теперь я озадачен.
Забудьте в течение одной секунды управляемой среды и вернитесь к native. Почему InterlockedIncrement64
не может работать, но InterlockedExchangeAdd64
делает? InterlockedIncrement64
- макрос, если внутренние свойства недоступны и InterlockedExchangeAdd64
работает, то он может быть реализован как вызов InterlockedExchangeAdd64
...
Вернемся к управляемому: как выполняется 64-разрядное увеличение атома на 32-битных системах? Я полагаю, что предложение "Эта функция является атомарной по отношению к вызовам других взаимосвязанных функций", но все же я не видел никакого кода (спасибо Хансу указать на более глубокую реализацию), чтобы сделать это. Выберем InterlockedExchangedAdd64
реализацию из WinBase.h, когда внутренние функции недоступны:
FORCEINLINE
LONGLONG
InterlockedExchangeAdd64(
_Inout_ LONGLONG volatile *Addend,
_In_ LONGLONG Value
)
{
LONGLONG Old;
do {
Old = *Addend;
} while (InterlockedCompareExchange64(Addend,
Old + Value,
Old) != Old);
return Old;
}
Как он может быть атомарным для чтения/записи?