为什么即使在调用Close()后,等待ManualResetEvent的线程仍继续等待? [英] Why do threads waiting on a ManualResetEvent continue waiting even when Close() is called?
问题描述
今天我们很惊讶地得知,等待ManualResetEvent
的线程即使在事件关闭时仍继续等待该事件.我们本来希望调用Close()
会隐式地发出等待线程的信号.
We were surprised to learn today that threads waiting on a ManualResetEvent
continue waiting on the event even when it's closed. We would have expected that calling Close()
would implicitly signal the waiting threads.
我们对此进行了跟踪,原因是我们的某些Windows服务没有如我们所希望的那样快速关闭.我们将更改所有关闭ManualResetEvent
引用的Dispose
实现,以首先调用Set
.
We tracked this down as a reason some of our windows services were not shutting down as fast as we'd like. We're changing all of our Dispose
implementations that close ManualResetEvent
references to call Set
first.
谁能解释为什么Close
不隐式调用Set
吗?您希望什么时候等待的线程继续等待?
Can anyone explain why Close
doesn't implicitly call Set
? When would you want a waiting thread to continue waiting?
这是我们的测试代码,以证明我们的发现:
Here's our test code to demonstrate our findings:
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
调用的情况下运行此代码时,就会得到此代码.
When we run this code with the Set
call commented, we get this..
0 Main sleeping 100
0 ThreadPool enter, waiting 250ms...
103 Main about to close
103 Main waiting for exit 500ms
259 ThreadPool exit
当我们显式调用Set
时,我们得到了这个..
When we explicitly call Set
we get this..
0 Main sleeping 100
0 ThreadPool enter, waiting 250ms...
98 Main about to close
98 ThreadPool exit
98 Main waiting for exit 500ms
推荐答案
Close
是处置对象的一种方法(该类上的Close
和Dispose
产生相同的行为).它不影响句柄的状态.假设在所有情况下,用户都希望线程在我关闭的句柄上等待继续,这似乎是不合理的.实际上,该句柄已被使用 的事实应表明您不应该一开始就调用Close
.
Close
is a means of disposing of the object (Close
and Dispose
on this class yield identical behavior). It does not affect the state of the handle. To assume that, in all cases, the user would want a thread waiting on a handle that I closed to continue does not seem reasonable. In fact, the fact that the handle is in use should indicate that you shouldn't be calling Close
in the first place.
这与为什么不应该隐式调用Set
吗?"无关紧要,这是一个概念性的问题:如果您要调用Close
,则您将不再关心该对象.使用Set
和Reset
控制线程之间的执行流;在不再使用Close
(或Dispose
)之前,不要在任何包含WaitHandle
的对象上调用Close
(或Dispose
).
It's not a matter of "why shouldn't Set
be called implicitly?", it's a conceptual problem: If you're calling Close
, you should no longer care about the object. Use Set
and Reset
to control the flow of execution among threads; don't call Close
(or Dispose
) on any object, WaitHandle
s included, until they are no longer in use.
这篇关于为什么即使在调用Close()后,等待ManualResetEvent的线程仍继续等待?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!