2009-06-24 16 views
5

¿La implementación es segura para subprocesos? Si no, ¿qué es lo que me estoy perdiendo? ¿Debo tener las palabras clave volatile en alguna parte? ¿O un bloqueo en algún lugar del método OnProcessingCompleted? ¿Si es así, donde?C#: eventos seguros contra subprocesos

public abstract class ProcessBase : IProcess 
{ 
    private readonly object completedEventLock = new object(); 

    private event EventHandler<ProcessCompletedEventArgs> ProcessCompleted; 

    event EventHandler<ProcessCompletedEventArgs> IProcess.ProcessCompleted 
    { 
     add 
     { 
      lock (completedEventLock) 
       ProcessCompleted += value; 
     } 
     remove 
     { 
      lock (completedEventLock) 
       ProcessCompleted -= value; 
     } 
    } 

    protected void OnProcessingCompleted(ProcessCompletedEventArgs e) 
    { 
     EventHandler<ProcessCompletedEventArgs> handler = ProcessCompleted; 
     if (handler != null) 
      handler(this, e); 
    } 
} 

Nota: La razón por la que tengo evento privado y cosas por el interfaz explícita, se debe a que es una clase base abstracta. Y las clases que heredan de él no deberían hacer nada directamente con ese evento. Se ha añadido el contenedor de clase para que sea más claro =)

+0

(respondió al comentario) –

Respuesta

4

No hay necesidad de que el ProcessCompleted miembro privado para ser un event - que sólo podría ser un campo: - dentro de la clase que siempre va directamente al campo , así que las cosas event se pierden de todos modos.

El enfoque que has demostrado con un objeto de bloqueo explícito no es mucho más seguro para subprocesos que sólo tener un evento de campo como (es decir public event EventHandler<ProcessCompletedEventArgs> ProcessCompleted; - la única diferencia es que no se está fijando "este" (que es una buena cosa - usted debe idealmente evitar el bloqueo en this). .. el enfoque de "variable de manipulador" es la correcta, pero todavía hay side-effects you should be aware of

+0

Agregué por qué utilicé el gestor de eventos privado y el material de evento explícito a mi pregunta. ¿Todavía no es necesario? ¿Y a qué te refieres con esa diferencia? ¿Un evento público EventHandler SomeEvent se bloquea automáticamente? – Svish

+2

Sí; los eventos de tipo campo (es decir, un evento sin una adición/eliminación explícita) tienen un bloqueo incorporado (esto); ver 10.8.1 en la especificación del idioma (versión MS); sin embargo, esto es pasado por alto por el código dentro de la clase; consulte http://marcgravell.blogspot.com/2009/02/fun-with-field-like-events.html; así como un evento * privado *, el agregar/quitar (y así bloquear) nunca se usa. Para una implementación de interfaz explícita, el código está bien, y usted debería agregar el bloqueo usted mismo, lo que ha hecho, y podría decirse que es * mejor * que un "bloqueo (esto)". Quédese con él ;-p –

+0

alrighty =) – Svish

5

debe bloquear al recuperar el manejador demasiado De lo contrario, es posible que no tenga el último valor:

protected void OnProcessingCompleted(ProcessCompletedEventArgs e) 
{ 
    EventHandler<ProcessCompletedEventArgs> handler; 
    lock (completedEventLock) 
    { 
     handler = ProcessCompleted; 
    } 
    if (handler != null) 
     handler(this, e); 
} 

Tenga en cuenta que este no prevenir una condición de carrera en la que hemos decidido que vamos a ejecutar un conjunto de controladores y luego un manejador de baja. Todavía se llamará, porque hemos buscado el delegado de multidifusión que lo contiene en la variable handler.

No hay mucho que pueda hacer al respecto, salvo hacer que el manejador sepa que ya no se debe llamar.

Podría decirse que es mejor no intentar para hacer los eventos flujos seguros - especificar que la suscripción debe única cambio en el hilo que va a provocar el evento.

+0

¿Está seguro, el bloqueo es necesario? Los delegados son inmutables y la asignación es operación atómica, por lo que no creo que sea necesario el bloqueo. – TcKs

+0

Mira mis comentarios a tu post. Necesitas bloquearlo para que sea seguro para hilos. –

+0

Sí, los bloqueos en "agregar" y "eliminar" son necesarios. Pero, ¿qué beneficio obtuve al usar "bloqueo" en "OnProcessingCompleted"? – TcKs

Cuestiones relacionadas