为什么即使在调用Close()后,等待ManualResetEvent的线程仍继续等待? [英] Why do threads waiting on a ManualResetEvent continue waiting even when Close() is called?

查看:96
本文介绍了为什么即使在调用Close()后,等待ManualResetEvent的线程仍继续等待?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

今天我们很惊讶地得知,等待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是处置对象的一种方法(该类上的CloseDispose产生相同的行为).它不影响句柄的状态.假设在所有情况下,用户都希望线程在我关闭的句柄上等待继续,这似乎是不合理的.实际上,该句柄已被使用 的事实应表明您不应该一开始就调用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,则您将不再关心该对象.使用SetReset控制线程之间的执行流;在不再使用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, WaitHandles included, until they are no longer in use.

这篇关于为什么即使在调用Close()后,等待ManualResetEvent的线程仍继续等待?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆