Leyendo this question, quería probar si podía demostrar la no atomicidad de lecturas y escrituras en un tipo para el que no se garantiza la atomicidad de tales operaciones.¿Por qué este código no demuestra la no atomicidad de las lecturas/escrituras?
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;
}
}
Para mi sorpresa, la afirmación se negó a fallar incluso después de tres minutos completos de ejecución. ¿Qué ofrece?
- La prueba es incorrecta.
- Las características de tiempo específicas de la prueba hacen que sea poco probable/imposible que la afirmación falle.
- La probabilidad es tan baja que tengo que ejecutar la prueba durante mucho más tiempo para que sea probable que se active.
- El CLR proporciona garantías más sólidas sobre la atomicidad que la especificación de C#.
- Mi SO/hardware ofrece garantías más sólidas que el CLR.
- ¿Algo más?
Por supuesto, no pretendo confiar en ningún comportamiento que no esté explícitamente garantizado por la especificación, pero me gustaría obtener una comprensión más profunda del problema.
FYI, me encontré con esto en ambos de depuración y de lanzamiento (cambiando Debug.Assert
a if(..) throw
) perfiles en dos entornos diferentes:
- de Windows 7 64-bit + .NET 3.5 SP1
- Windows XP 32-bit + .NET 2,0
EDIT: para excluir la posibilidad de que el comentario de John Kugelman "el depurador no es Schrodinger-safe" el principal problema, he añadido la línea someList.Add(dCopy);
al método KeepReading
y verificación fied que esta lista no estaba viendo un solo valor obsoleto de la memoria caché.
EDITAR: Basado en la sugerencia de Dan Bryant: El uso de long
en lugar de double
lo rompe de forma casi instantánea.
Mi conjetura (y es mucho más que eso) es # 3. – AakashM
Revisaría el IL para asegurarme de que el compilador no jugara ningún truco, pero aparte de eso no obtuve nada. Esperaría que esto se rompa en una máquina de 32 bits. – mquander
Aumentaría el número de hilos de escritura: trate de mantener N + 1 hilos ejecutándose en un sistema N-core. –