Пусть следующий код (обратите внимание, что это только пример кода):Использование Volatile.Write() вместо летучих в C#
public async void UnsafeMethod()
{
int unsafeValue = 0;
Task.Run(() => unsafeValue = 42); // set unsafeValue to some value
await Task.Delay(10); // wait for some time
Assert.AreEqual(42, unsafeValue); // check if unsafeValue has the new value
}
(Предположим здесь, что процессор находится в режиме ожидания и немедленно выполняет задачу .)
Поскольку задача будет выполнена в новом потоке, новое значение unsaveValue
может быть не видно другим темам из-за возможных проблем с кешированием. Если я хочу, чтобы сделать изменения видимыми, я бы использовать volatile
и сделать локальную переменную поле: (. Опять Предположим, что задача выполняется немедленно)
private volatile int safeValue = 0;
public async void SafeMethod()
{
Task.Run(() => safeValue = 42); // set safeValue to some value
await Task.Delay(10); // wait for some time
Assert.AreEqual(42, safeValue); // check if safeValue has the new value
}
Мой вопрос сейчас, если следующий будет делать то же самое, сохраняя при этом локальном переменном (я знаю, что компилятор делает это поле в любом случае ...):
public async void AnotherMethod()
{
int safeValue = 0;
Task.Run(() => Volatile.Write(ref safeValue, 42); // set safeValue to some value
await Task.Delay(10); // wait for some time
Assert.AreEqual(42, safeValue); // check if safeValue has the new value
}
(Task получает немедленно казнен.)
Документация мне не совсем понятна. https://msdn.microsoft.com/en-us/library/system.threading.volatile(v=vs.110).aspx
Она гласит:
На многопроцессорной системе, летучий операция записи гарантирует, что значение, записанное в ячейку памяти сразу виден всем процессоров.
Это то, что я хочу. Однако в нем также указывается:
Записывает указанное значение в указанное поле. В системах, которые требуется , вставляет защитный барьер памяти, который препятствует процессору от операций переупорядочивания памяти следующим образом: если чтение или запись появляется до этого метода в коде, процессор не может переместить его после этого метода.
в описании метода, которое я не уверен, что это то, что я хочу.
Снова мой вопрос: будет ли последний отрезанный код делать то, что я хочу его сделать (сделать запись сразу видимой для других потоков)?
Вы определенно хотите использовать 'Volatile.Write()' вместо 'volatile'. Фактически, [Эрик Липперт говорит, что вам следует избегать «volatile») (https://blogs.msdn.microsoft.com/ericlippert/2011/06/16/atomicity-volatility-and-immutability-are-different-part-three /). –
IMHO, 'Assert.AreEqual (42, safeValue);' не знает о вызове 'Volatile.Write', поэтому' safeValue' может быть кэширован. Я думаю, что 'Volatile.Read' (когда вы вызываете' Assert.AreEqual') ... –
Matteo правильный - вам нужно использовать 'Volatile.Write()' для каждой записи и 'Volatile.Read()' для чтения (для поля, совместно используемого потоком). –