2011-01-06 12 views
6

¿Este subproceso de método de extensión es seguro?¿El subproceso del método de extensión es seguro?

public static class Extensions 
    { 
     public static void Raise<T>(this EventHandler<T> handler, 
     object sender, T args) where T : EventArgs 
     { 
     if (handler != null) handler(sender, args); 
     } 
    } 

o necesito cambiarlo a esto?

public static class Extensions 
    { 
     public static void Raise<T>(this EventHandler<T> handler, 
     object sender, T args) where T : EventArgs 
     { 
     var h = handler; 
     if (h!= null) h(sender, args); 
     } 
    } 
+0

diseño e implementación detalles de eventos con respecto a enhebrar http://stackoverflow.com/questions/786383/c-events-and-thread-safety – user44298

Respuesta

9

Has encontrado un agujero de bucle interesante, ha hecho tropezar a todo el mundo. No, no es seguro para subprocesos.

Mientras que parece como EventHandler <> la referencia se copia mediante el argumento de método, esto no es lo que sucede en el tiempo de ejecución. Los métodos de extensión están sujetos a estar en línea, al igual que un método de instancia regular. De hecho, es extremadamente susceptible de ser incluido porque es muy pequeño. No hay copia, tienes que hacer una tú mismo.

+1

No estoy seguro de que tenga razón. Esto solo se aplicaría cuando la función de llamada estuviera llamando al método sobre un valor que estaría sujeto a modificación por otro hilo (un campo de clase, por ejemplo, en lugar de una variable local). No sé si el JIT podría hacer una llamada así en ese caso. – tster

+0

Sin embargo, este es un tema muy interesante. Ojalá no estuviera en el trabajo y tuviera tiempo para profundizar más en esto. – tster

+1

Bueno, de eso se trata la prueba nula en el código de generación de eventos. –

7

Ninguna de las versiones es segura para roscas, dependiendo de lo que quiere decir con "threadsafe". Considere su segunda versión:

var h = handler;   
    if (h!= null) 
     h(sender, args); 

"controlador" es una copia de un campo que tiene un delegado inmutable. Supongamos que ese campo está mutado a "nulo" en otro hilo después de la verificación nula. Su código no falla en ese caso, porque ha realizado una copia del valor original no nulo. Pero simplemente no estrellarse no hace que el programa hilo seguro. Un programa que no se cuelga pero todavía produce los resultados incorrectos todavía no es seguro.

Supongamos que cuando el otro subproceso establece el campo de evento en nulo, también muta un estado que el contenido anterior necesitaba para ejecutarse correctamente. Ahora va a ejecutar un controlador de eventos que depende del estado que acaba de mutar en otro hilo; está ejecutando un controlador de eventos obsoleto.

No hay una manera fácil de protegerse contra este problema; si esa es la situación en la que se encuentra, entonces tendrá que diseñar su lógica de enhebrado con mucho cuidado para poder manejar la situación.

Cuestiones relacionadas