C #: Thread-sichere Veranstaltungen
-
10-07-2019 - |
Frage
Ist die Umsetzung unter Thread-sicher? Wenn nicht, was bin ich dabei? Sollte ich die volatile
Keywords irgendwo haben? Oder ein Schloss irgendwo in der OnProcessingCompleted
Methode? Wenn ja, wo?
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 von ihm erben sollen nicht mit diesem Fall direkt nichts tun. Hinzugefügt Wrapper die Klasse, so dass es klar ist =)
Lösung
Es besteht keine Notwendigkeit für das private ProcessCompleted
Mitglied eine event
zu sein - es ist nur ein Bereich sein könnte. private EventHandler<ProcessCompletedEventArgs> ProcessCompleted;
- innerhalb der Klasse geht es immer gerade auf das Feld, so dass 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" (das ist eine gute Sache - sollten Sie ideal vermeiden auf this
Verriegelung) .. der "handler Variable" Ansatz ist die richtige, aber es gibt immer noch a href = "http <: //blogs.msdn.com/ericlippert/archive/2009/04/29/events-and-races.aspx“rel = "nofollow noreferrer"> Nebenwirkungen sollten Sie sich bewusst sein .
Andere Tipps
Sie müssen sperren, wenn Sie den Handler holen, sonst können Sie nicht den neuesten Wert haben:
protected void OnProcessingCompleted(ProcessCompletedEventArgs e)
{
EventHandler<ProcessCompletedEventArgs> handler;
lock (completedEventLock)
{
handler = ProcessCompleted;
}
if (handler != null)
handler(this, e);
}
Beachten Sie, dass diese nicht verhindern eine Race-Bedingung, wo wir entschieden haben, werden wir eine Reihe von Behandlungsroutinen und dann ausführen ein Handler unsubscribed. Es wird noch genannt werden, weil wir die Multicastdelegat in die handler
Variable geholt haben enthalten.
Es gibt nicht viel Sie dies tun können, außer macht den Handler selbst bewusst, dass es nicht mehr aufgerufen werden soll.
Es ist wohl besser, nur nicht versuchen die Ereignisse Thread-sicher zu machen - angeben, dass das Abonnement sollte nur Änderung des Threads, das Ereignis auslösen wird.