Что на самом деле гарантировано для изменчивого поля в c#? - PullRequest
3 голосов
/ 14 января 2020

Я запутался с документацией для .NET / C# относительно ключевого слова volatile против System.Threading.Thread.VolatileRead / VolatileWrite и System.Threading.Volatile.Read/Write. Я пытаюсь понять, что именно гарантировано для изменчивого поля и что именно делают эти методы.

Я думал, volatile предоставляет семантику выпуска / приобретения, но документацию для Thread.VolatileRead / VolatileWrite заставляет меня задуматься, верно ли мое понимание.

Это справочник по языку для volatile: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/volatile

Добавление модификатора volatile гарантирует, что все потоки будет наблюдать изменчивые записи, выполненные любым другим потоком в порядке, в котором они были выполнены. Нет гарантии единого общего порядка изменчивых записей, как видно из всех потоков выполнения.

Пока что имеет смысл. Это языковая спецификация: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/classes#volatile -поля

Для энергозависимых полей такая оптимизация переупорядочения ограничена:

Чтение энергозависимого поля называется изменчивое чтение. Изменчивое чтение имеет «приобретенную семантику»; то есть гарантированно произойдет до любых ссылок на память, которые появляются после нее в последовательности команд. Запись изменяемого поля называется изменяемой записью. У изменчивой записи есть "семантика выпуска"; то есть гарантированно произойдет после любых ссылок на память перед инструкцией записи в последовательности команд.

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

Опять же, похоже, что volatile обеспечивает семантику освобождения / получения.

Но потом я смотрю документацию для Thread.VolatileRead: https://docs.microsoft.com/en-us/dotnet/api/system.threading.thread.volatileread?view=netframework-4.8#System_Threading_Thread_VolatileRead_System_Int64__

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

Для Thread.VolatileWrite:

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

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

В C# использование модификатора volatile в поле гарантирует, что весь доступ к этому полю использует VolatileRead или VolatileWrite

Так что мой Вопрос в том, что гарантировано для поля volatile относительно буфера хранилища - просто отпустите / заполучите или более сильные гарантии Thread.VolatileRead / Write? Или мое понимание о VolatileRead/Write неверно и совпадает с volatile?

1 Ответ

0 голосов
/ 14 января 2020
  1. Нет разницы между System.Threading.Thread.VolatileRead/VolatileWrite и System.Threading.Volatile.Read/Write - это идентичные вспомогательные методы, которые перед чтением или записью имитируют c полный барьер памяти (необязательно инструкция MFENCE). Вот внутренняя реализация:
public static void VolatileWrite(ref sbyte address, sbyte value)
{
  Thread.MemoryBarrier();
  address = value;
}

Переменная volatile использует (-ed) семантику получения / выпуска в устаревшей архитектуре процессора IA (Itanium) с более слабой моделью памяти.

При большинстве В популярной архитектуре x86 модификатор volatile позволяет избежать оптимизации компилятора, а также может использовать инструкции с префиксом lock для обеспечения согласованности.

В общем, компилятор может использовать различные приемы для соответствия с C# моделью памяти , которая гласит:

Никакие операции чтения или записи не могут двигаться до volatile чтения или после volatile write Все записи имеют эффект volatile write
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...