2010-08-29 12 views
6

Tengo una pregunta relacionada con el modelo de la memoria C# y los hilos. No estoy seguro de si el siguiente código es correcto sin la palabra clave volátil.Modelo de memoria C# y variable no volátil inicializada antes de la creación del otro hilo

public class A { 
    private int variableA = 0; 

    public A() { 

    variableA = 1; 

    Thread B = new Thread(new ThreadStart(() => printA())).Start(); 
    } 

    private void printA() { 
    System.Console.WriteLine(variableA); 
    } 
} 

Mi preocupación es si se garantiza que el hilo B verá variableA con valor 1 sin utilizar volátil? En el hilo principal solo estoy asignando 1 a variableA en el constructor. Después de eso, no estoy tocando la variable A, solo se usa en el hilo B, por lo que probablemente no sea necesario el bloqueo.

Pero, ¿está garantizado que el hilo principal va a vaciar su caché y escribir los contenidos de la variable A en la memoria principal, para que el segundo hilo pueda leer el valor recién asignado?

Además, ¿se garantiza que el segundo hilo leerá los contenidos de la variable A de la memoria principal? ¿Pueden producirse algunas optimizaciones del compilador y el subproceso B puede leer los contenidos de la variableA del caché en lugar de la memoria principal? Puede suceder cuando se cambia el orden de las instrucciones.

Por supuesto, agregando volátil a la variable Una declaración hará que el código sea correcto. Pero, ¿es necesario? Lo estoy preguntando porque escribí un código con algunas inicializaciones de variables no volátiles en el constructor, y las variables son utilizadas más tarde por algunos subprocesos del temporizador, y no estoy seguro si es totalmente correcto.

¿Qué pasa con el mismo código en Java?

Gracias, Michal

Respuesta

4

El mismo código en Java es, sin duda bien - la creación de un nuevo hilo actúa como una especie de barrera, de manera efectiva. (Todas las acciones anteriores en el texto del programa que la creación del hilo "suceden antes" se inicia el nuevo hilo.)

No sé lo que está garantizado en .NET con respecto a la creación de nuevos hilos, sin embargo. Aún más preocupante es la posibilidad de una lectura retrasada al usar Control.BeginInvoke y similares ... No he visto ninguna garantía en torno a las barreras de memoria para esas situaciones.

Para ser honesto, I sospechoso está bien. Sospecho que cualquier cosa que necesite coordinarse entre hilos como este (ya sea crear uno nuevo o coordinar una llamada a uno existente) usará una barrera de memoria completa en ambos hilos implicados. Sin embargo, tiene toda la razón al preocuparse, y espero que obtenga una respuesta más definitiva de alguien más inteligente que yo. Es posible que desee enviar por correo electrónico Joe Duffy para obtener su punto de vista sobre este ...

+0

Sí, sospecho lo mismo, pero quiero estar seguro. Le enviaré un correo electrónico, gracias. –

4

embargo, es que garantiza que el hilo principal hará que se vacíe su caché y escribir el contenido variableA a la memoria principal,

Sí, esto está garantizado por el modelo de memoria MS CLR. No necesariamente para otras implementaciones de la CLI (es decir, no estoy seguro acerca de Mono). El estándar ECMA no lo requiere.

para que el segundo hilo pueda leer el valor recién asignado?

Eso requiere que la memoria caché se haya actualizado. Probablemente esté garantizado por la creación del hilo (como dijo Jon Skeet).Sin embargo, no está garantizado por el punto anterior. La memoria caché se vacía en cada escritura, pero no en cada lectura.

Puede estar seguro utilizando VolatileRead(ref variableA), pero se recomienda (Jeffrey Richter) usar la clase Interlocked. Tenga en cuenta que VolatileWrite() es superfluo en MS.NET.

5

Hay muchos lugares donde se crean barreras de memoria implícitas. Este es uno de ellos. Los hilos iniciales crean barreras completas. Por lo tanto, la escritura a variableA se confirmará antes de que se inicie el hilo y las primeras lecturas se obtendrán de la memoria principal. Por supuesto, en la implementación de Microsoft de la CLR es algo discutible porque las escrituras ya tienen una semántica volátil. Pero la misma garantía no se establece en la especificación ECMA, por lo que es teóricamente posible que la implementación de Mono se comporte de manera diferente a este respecto.

Mi preocupación es que si se garantiza que el hilo B verá variableA con valor 1 sin utilizar volátil?

En este caso ... sí. Sin embargo, si continúa utilizando variableA en el segundo hilo, no hay garantía después de la primera lectura de que verá actualizaciones.

embargo, es que garantiza que el principal hilo hará que se vacíe su caché y escribir el contenido variableA a la memoria principal , por lo que el segundo hilo puede leer el valor recién asignado?

Sí.

Además, se garantizó que el segundo hilo leerá los contenidos variableA desde la memoria principal ?

Sí, pero solo en la primera lectura.

Por supuesto, la adición volátil para la declaración variableA hará que el código correcta. Pero, ¿es necesario?

En este caso muy específico y estrecho ... no. Pero, en general, se recomienda utilizar la palabra clave volatile en estos escenarios. No solo hará que su código sea seguro para subprocesos a medida que el escenario se vuelva más complicado, sino que también ayuda a documentar el hecho de que el campo va a ser utilizado por más de un hilo y que ha considerado las implicaciones de usar un bloqueo. estrategia libre

+0

Hola Brian, "Sí, pero solo en la primera lectura". - ¿Podrías justificar esto de alguna manera? ¿Tienes algunos enlaces? –

Cuestiones relacionadas