Читая этот вопрос, я хотел проверить, смогу ли я продемонстрировать -атомарность операций чтения и записи для типа, для которого атомарность таких операций не гарантируется.
private static double _d;
[STAThread]
static void Main()
{
new Thread(KeepMutating).Start();
KeepReading();
}
private static void KeepReading()
{
while (true)
{
double dCopy = _d;
// In release: if (...) throw ...
Debug.Assert(dCopy == 0D || dCopy == double.MaxValue); // Never fails
}
}
private static void KeepMutating()
{
Random rand = new Random();
while (true)
{
_d = rand.Next(2) == 0 ? 0D : double.MaxValue;
}
}
К моему удивлению, утверждение не сработало даже после полных трех минут выполнения. Что дает?
- Тест неверный.
- Конкретные временные характеристики теста делают маловероятным/невозможным, что утверждение не будет выполнено.
- Вероятность настолько мала, что мне приходится запускать тест гораздо дольше, чтобы повысить вероятность того, что он сработает.
- CLR обеспечивает более сильные гарантии атомарности, чем спецификация C#.
- Моя ОС/оборудование обеспечивает более надежные гарантии, чем CLR.
- Что-то другое?
Конечно, я не собираюсь полагаться на какое-либо поведение, явно не гарантированное спецификацией, но хотелось бы более глубокого понимания вопроса.
К вашему сведению, я запустил это как в профилях Debug, так и в Release (изменив Debug.Assert
на if(..) throw
) в двух разных средах:
- Windows 7 64-разрядная + .NET 3.5 SP1
- Windows XP 32-разрядная + .NET 2.0
РЕДАКТИРОВАТЬ: Чтобы исключить вероятность того, что комментарий Джона Кугельмана «отладчик не является безопасным для Шредингера» может быть проблемой, я добавил строку someList.Add(dCopy);
в метод KeepReading
и убедился, что в этом списке нет ни одного устаревшего значения из кеша.
РЕДАКТИРОВАТЬ: на основе предложения Дэна Брайанта: использование long
вместо double
практически мгновенно ломает его.