Мы были удивлены, узнав сегодня, что потоки, ожидающие на ManualResetEvent
, продолжают ожидать события, даже когда оно закрыто. Мы ожидали бы, что вызов Close()
будет неявно сигнализировать ожидающим потокам.
Мы отследили это как причину, по которой некоторые из наших оконных сервисов не закрывались так быстро, как хотелось бы. Мы меняем все наши Dispose
реализации, которые закрывают ManualResetEvent
ссылки для вызова Set
в первую очередь.
Может кто-нибудь объяснить, почему Close
не вызывает неявно Set
? Когда вы хотите, чтобы ожидающий поток продолжал ждать?
Вот наш тестовый код, демонстрирующий наши выводы:
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);
}
Когда мы запускаем этот код с комментарием Set
, мы получаем это ..
0 Main sleeping 100
0 ThreadPool enter, waiting 250ms...
103 Main about to close
103 Main waiting for exit 500ms
259 ThreadPool exit
Когда мы явно вызываем Set
, мы получаем это ..
0 Main sleeping 100
0 ThreadPool enter, waiting 250ms...
98 Main about to close
98 ThreadPool exit
98 Main waiting for exit 500ms