2010-06-07 25 views
5

Según tengo entendido, el modelo de memoria .NET en una máquina de 32 bits garantiza que las escrituras y lecturas de palabras de 32 bits sean operaciones atómicas pero no proporcionar esta garantía en palabras de 64 bits. He escrito una herramienta rápida para demostrar este efecto en un sistema operativo Windows XP de 32 bits y obtengo resultados consistentes con la descripción de ese modelo de memoria..NET 3.5SP1 Modelo de memoria de 64 bits en comparación con el modelo de memoria de 32 bits

Sin embargo, he tomado el ejecutable de esta misma herramienta y lo ejecuto en un sistema operativo Windows 7 Enterprise de 64 bits y estoy obteniendo resultados muy diferentes. Ambas máquinas son especificaciones idénticas solo con diferentes sistemas operativos instalados. Hubiera esperado que el modelo de memoria .NET garantizaría escrituras y lecturas tanto AMBAS palabras de 32 bits como de 64 bits para ser atómico en un sistema operativo de 64 bits. Encuentro resultados completamente contrarios a AMBAS suposiciones. Las lecturas y escrituras de 32 bits no son atómicas en este sistema operativo.

¿Puede alguien explicarme por qué esto falla en un sistema operativo de 64 bits?

Código herramienta:

using System; 
using System.Threading; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var th = new Thread(new ThreadStart(RunThread)); 
      var th2 = new Thread(new ThreadStart(RunThread)); 
      int lastRecordedInt = 0; 
      long lastRecordedLong = 0L; 
      th.Start(); 
      th2.Start(); 
      while (!done) 
      { 
       int newIntValue = intValue; 
       long newLongValue = longValue; 
       if (lastRecordedInt > newIntValue) Console.WriteLine("BING(int)! {0} > {1}, {2}", lastRecordedInt, newIntValue, (lastRecordedInt - newIntValue)); 
       if (lastRecordedLong > newLongValue) Console.WriteLine("BING(long)! {0} > {1}, {2}", lastRecordedLong, newLongValue, (lastRecordedLong - newLongValue)); 
       lastRecordedInt = newIntValue; 
       lastRecordedLong = newLongValue; 
      } 
      th.Join(); 
      th2.Join(); 
      Console.WriteLine("{0} =? {2}, {1} =? {3}", intValue, longValue, Int32.MaxValue/2, (long)Int32.MaxValue + (Int32.MaxValue/2)); 
     } 

     private static long longValue = Int32.MaxValue; 
     private static int intValue; 
     private static bool done = false; 

     static void RunThread() 
     { 
      for (int i = 0; i < Int32.MaxValue/4; ++i) 
      { 
       ++longValue; 
       ++intValue; 
      } 
      done = true; 
     } 
    } 
} 

Resultados en Windows XP de 32 bits:

Windows XP 32-bit 
Intel Core2 Duo P8700 @ 2.53GHz 
BING(long)! 2161093208 > 2161092246, 962 
BING(long)! 2162448397 > 2161273312, 1175085 
BING(long)! 2270110050 > 2270109040, 1010 
BING(long)! 2270115061 > 2270110059, 5002 
BING(long)! 2558052223 > 2557528157, 524066 
BING(long)! 2571660540 > 2571659563, 977 
BING(long)! 2646433569 > 2646432557, 1012 
BING(long)! 2660841714 > 2660840732, 982 
BING(long)! 2661795522 > 2660841715, 953807 
BING(long)! 2712855281 > 2712854239, 1042 
BING(long)! 2737627472 > 2735210929, 2416543 
1025780885 =? 1073741823, 3168207035 =? 3221225470 

Observe cómo BING (int) nunca se escribe y demuestra que el 32-bit lecturas/escrituras son atómicas en este sistema operativo de 32 bits.

Resultados en Windows 7 Enterprise de 64 bits:

Windows 7 Enterprise 64-bit 
Intel Core2 Duo P8700 @ 2.53GHz 
BING(long)! 2208482159 > 2208121217, 360942 
BING(int)! 280292777 > 279704627, 588150 
BING(int)! 308158865 > 308131694, 27171 
BING(long)! 2549116628 > 2548884894, 231734 
BING(int)! 534815527 > 534708027, 107500 
BING(int)! 545113548 > 544270063, 843485 
BING(long)! 2710030799 > 2709941968, 88831 
BING(int)! 668662394 > 667539649, 1122745 
1006355562 =? 1073741823, 3154727581 =? 3221225470 

Aviso que Bing (largo) y Bing (int) aparecerán en la pantalla! ¿Por qué fallan las operaciones de 32 bits, y mucho menos las de 64 bits?

+0

¿Es posible que edite su pregunta para usar el formato de 'Código de muestra' en la barra de herramientas? Es increíblemente difícil de leer ... – JBRWilkinson

+0

Lo he formateado correctamente, pero con caracteres TAB inicialmente en lugar de espacios y la vista previa se veía genial. Me sorprendió cuando descubrí que no se publicó por completo. Lo arreglé ahora. –

+0

Ya lo tuve arreglado: D – Femaref

Respuesta

4

En su devolución de llamada hilo que están haciendo mucho más que simplemente escribiendo o leyendo:

++longValue; 
++intValue; 

Haciendo lectura y la escritura no se puede garantizar que sea atómica. Use Interlocked.Increment para asegurar la atomicidad de esta operación.

+0

No quiero que esas líneas sean explícitamente atómicas. Quiero que la operación de escritura sea garantizada atómica por el modelo de memoria. Eso es lo que trato de demostrar. Obviamente debería usar Interlocked.Increment (ref intValue o longValue) pero eso vencería el propósito de la demostración. –

+3

La operación de escritura es atómica, es la lectura + escritura que no es, como dijo Darin. Por lo tanto, si lee el valor 5 en el hilo uno, increméntelo a 6, ya que no es el hilo atómico 2, puede haber leído el valor 5 mientras tanto y ya lo incrementó a 6 o más. Así que el hilo 1 está restableciendo el valor a un valor anterior, explicando el comportamiento que estás viendo. –

+0

@Julien Sí, pero el caso que se prueba en el hilo Console.WriteLine principal es que el último valor registrado nunca debe ser mayor que el valor más reciente. ¿Puedes explicar las grandes diferencias observadas en los valores? Ese es el último valor en las líneas de salida. No está apagado por uno o dos, está en el orden de 1,000 o 100,000, lo que indica que se están produciendo algunos daños serios. –

Cuestiones relacionadas