Wir waren überrascht, heute zu erfahren, dass Threads, die auf einen ManualResetEvent
warten, auf das Ereignis warten, selbst wenn es geschlossen ist. Wir hätten erwartet, dass der Aufruf von Close()
implizit die wartenden Threads signalisiert.Warum warten Threads, die auf ein ManualResetEvent warten, auch wenn Close() aufgerufen wird?
Wir haben dies als Grund dafür festgestellt, dass einige unserer Windows-Dienste nicht so schnell heruntergefahren wurden, wie wir es gerne hätten. Wir ändern alle unsere Dispose
Implementierungen, die ManualResetEvent
Referenzen schließen, zuerst Set
aufrufen.
Kann jemand erklären, warum Close
nicht implizit Set
aufrufen? Wann möchten Sie, dass ein wartender Thread weiter wartet?
Hier ist unser Testcode unsere Ergebnisse zu zeigen:
private static readonly Stopwatch _timer = Stopwatch.StartNew();
public static void Test()
{
var sync = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(state =>
{
Log("ThreadPool enter, waiting 250ms...");
sync.WaitOne(250);
Log("ThreadPool exit");
});
Log("Main sleeping 100");
Thread.Sleep(100);
Log("Main about to close");
// sync.Set(); // Is Set called implicitly? No...
sync.Close();
Log("Main waiting for exit 500ms");
Thread.Sleep(500);
}
private static void Log(string text)
{
Console.WriteLine("{0:0} {1}", _timer.ElapsedMilliseconds, text);
}
Wenn wir diesen Code ausführen mit der Set
Anruf kommentierte wir diese bekommen ..
0 Main sleeping 100
0 ThreadPool enter, waiting 250ms...
103 Main about to close
103 Main waiting for exit 500ms
259 ThreadPool exit
Wenn wir ausdrücklich Set
nennen wir bekommen dies ..
0 Main sleeping 100
0 ThreadPool enter, waiting 250ms...
98 Main about to close
98 ThreadPool exit
98 Main waiting for exit 500ms
Um das hinzuzufügen, würde es schwierig sein, Race-Bedingungen zu verfolgen, selbst im Beispiel des OP, würden Sie in Schwierigkeiten geraten, wenn die sync.Close(); zufällig aufgerufen, bevor der Thread-Pool herumgekommen ist, um sync.WaitOne() zu tun; – nos
Das Problem, das ich mit dieser ganzen Sache habe, ist, dass ein WaitHandle entworfen ist, um die Synchronisation zwischen Threads zu unterstützen, also fühle ich mich wie Set on Close und Event Wait after Close sollte implizit behandelt werden. Keine Sorge, wir haben eine benutzerdefinierte erweiterte Klasse erstellt, die die gewünschte Funktionalität hinzufügt. –
@Sam: Ich bin froh, dass Sie eine Lösung gefunden haben, aber das Problem ist, dass Ihre Philosophie über die Lebensdauer des Objekts nicht mit der der Designer übereinstimmt: die bloße Tatsache, dass Sie sich darum kümmern, in welchem Zustand sich der Griff befindet bedeutet, dass Sie aufgrund ihres Designs noch nicht bereit sind, 'Schließen' zu nennen. –