Ответ 1
Ну, вам не нужны блокировки обязательно, но если вы хотите, чтобы один поток определенно прочитал значение, которое написал другой поток, вам понадобятся блокировки или изменчивая переменная.
Я лично отказался от попыток понять точный смысл волатильности. Я стараюсь избегать написания собственного кода без блокировки, вместо этого полагаясь на экспертов, которые действительно понимают модель памяти.
EDIT: В качестве примера проблемы, которая может возникнуть, рассмотрите этот код:
using System;
using System.Threading;
public class Test
{
private static bool stop = false;
private bool Stop
{
get { return stop; }
set { stop = value; }
}
private static void Main()
{
Thread t = new Thread(DoWork);
t.Start();
Thread.Sleep(1000); // Let it get started
Console.WriteLine("Setting stop flag");
Stop = true;
Console.WriteLine("Set");
t.Join();
}
private static void DoWork()
{
Console.WriteLine("Tight looping...");
while (!Stop)
{
}
Console.WriteLine("Done.");
}
}
Эта программа может или не может завершиться. Я видел, как это происходит. Там нет гарантии, что поток чтения будет фактически прочитан из основной памяти - он может поместить начальное значение stop
в регистр и просто продолжать использовать это навсегда. Я видел это в действительности. Это не происходит на моих текущих машинах, но это может произойти в следующем.
Включение блокировок в свойство getter/setter в соответствии с кодом в вопросе сделает этот код правильным и его поведение будет предсказуемым.
Подробнее об этом см. в этом блоге Эрика Липперта.