2009-06-24 9 views
5

Ist die Implementierung unter Thread-sicher? Wenn nicht, was fehlt mir? Sollte ich irgendwo die volatile Schlüsselwörter haben? Oder ein Schloss irgendwo in der OnProcessingCompleted Methode? Wenn ja, wo?C#: Thread-sichere Ereignisse

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); 
    } 
} 

Hinweis: Der Grund, warum ich private Veranstaltung und explizite Schnittstelle Zeug haben, ist, weil es eine abstrakte Basisklasse ist. Und die Klassen, die davon erben, sollten nichts direkt mit diesem Ereignis tun. Hinzugefügt Wrapper die Klasse, so dass es klar ist =)

+0

(auf Kommentar geantwortet) –

Antwort

4

Es besteht keine Notwendigkeit für das private ProcessCompleted Mitglied ist ein event zu sein - es ist nur ein Feld sein könnte: - innerhalb der Klasse geht es direkt immer auf das Feld , so ist das event Zeug sowieso verloren.

Der Ansatz, den Sie mit einem expliziten Sperrobjekt gezeigt haben, ist nicht viel mehr Thread-sicher als nur ein Feld artiges Ereignis (dh public event EventHandler<ProcessCompletedEventArgs> ProcessCompleted; - der einzige Unterschied ist, dass Sie nicht Sperren „this“ sind (das ist eine gute Sache - Sie sollten ideal vermeiden sperren auf this). .. der „handler Variable“ Ansatz ist die richtige, aber es gibt immer noch side-effects you should be aware of

+0

Hinzugefügt, warum ich den privaten Eventhandler und das explizite Ereignis Zeug zu meiner Frage verwendet. Wird es immer noch nicht benötigt? Und was meinst du mit diesem Unterschied? Wird das Ereignis EventHandler SomeEvent von einem öffentlichen Ereignis automatisch gesperrt? – Svish

+2

Ja; feldähnliche Ereignisse (d. h. ein Ereignis ohne explizites Hinzufügen/Entfernen) hat eine eingebaute Sperre (dies); siehe 10.8.1 in der Sprachspezifikation (MS-Version); Dies wird jedoch durch Code innerhalb der Klasse umgangen - siehe http://marcgravell.blogspot.com/2009/02/fun-with-field-like-events.html; als * private * event wird das add/remove (und damit lock) nie benutzt. Für eine explizite Schnittstellenimplementierung ist der Code in Ordnung, und Sie müssten die Sperre selbst hinzufügen, was Sie getan haben - und wohl * besser * als eine "Sperre (das)". Bleib dran ;-p –

+0

alrighty =) – Svish

5

Sie müssen sperren, wenn Sie den Handler holen zu , sonst haben Sie möglicherweise nicht den neuesten Wert:

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

Beachten Sie, dass nicht verhindert eine Race-Bedingung, wo wir entschieden haben, dass wir eine Reihe von Handlern und dann einen Handler abgemeldet ausführen. Es wird immer noch aufgerufen, weil wir den Multicast-Delegaten, der es enthält, in die Variable handler abgerufen haben.

Es gibt nicht viel, was Sie dagegen tun können, außer dem Handler selbst bewusst zu machen, dass er nicht mehr aufgerufen werden sollte.

Es ist wohl besser, nur nicht versucht die Ereignisse Thread-sicher zu machen - angeben, dass das Abonnement sollte nur Änderung des Threads, das Ereignis auslösen wird.

+0

Bist du sicher, das Schloss ist notwendig? Die Delegierten sind unveränderlich und assignmend ist atomare Operation, also ist keine Sperre notwendig, denke ich. – TcKs

+0

Siehe meine Kommentare zu deinem Beitrag. Sie müssen unbedingt verriegeln, um es fadensicher zu machen. –

+0

Ja, die Sperren in "hinzufügen" und "entfernen" ist notwendig. Aber welchen Vorteil habe ich mit "lock" in "OnProcessingCompleted"? – TcKs