c# - 为什么等待 ManualResetEvent 的线程即使在调用 Close() 时也会继续等待?

标签 c# .net multithreading dispose

今天我们惊讶地得知等待 ManualResetEvent 的线程会继续等待该事件,即使它已关闭。我们本以为调用 Close() 会隐式地向等待线程发出信号。

我们追踪到这是我们的一些 Windows 服务没有像我们希望的那样快速关闭的原因。我们正在更改所有关闭 ManualResetEvent 引用的 Dispose 实现,以首先调用 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

最佳答案

Close 是一种处置对象的方式(CloseDispose 在此类上产生相同的行为)。它不影响句柄的状态。假设在所有情况下,用户都希望线程等待我关闭的句柄以继续运行,这似乎不合理。事实上,句柄正在使用 的事实表明您不应首先调用Close

这不是“为什么不应该隐式调用 Set?”的问题,这是一个概念问题:如果您正在调用 Close您不应该再关心这个对象。使用SetReset 来控制线程间的执行流程;不要对任何对象调用 Close(或 Dispose),包括 WaitHandle,直到它们不再被使用为止。

关于c# - 为什么等待 ManualResetEvent 的线程即使在调用 Close() 时也会继续等待?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2586306/

相关文章:

c# - Microsoft.Web.Administration 内存泄漏

c++ - 什么是 RPC 回调线程?

javascript - cefsharp 显示网站的困难

c# - 界面上的扩展方法未显示

c# - 如果 SelectionChanged 事件触发得太快,WPF Treeview 会溢出吗?

multithreading - 如果线程共享相同的PID,如何识别它们?

c# - Silverlight - 是否可以在后台线程上创建 UI 元素?

c# - 按出现次数对 IEnumerable 进行排序

asp.net - 从 GridView 获取值

c# - 从字符串反序列化 XML