【问题标题】:Dispose WaitHandle for basic thread synchronization为基本线程同步处理 WaitHandle
【发布时间】:2014-04-13 17:42:29
【问题描述】:

根据文档,.NET 中的 WaitHandle 应该显式/隐式处理。但是,我在以下基本同步任务中遇到了麻烦:

  • 线程上正在执行一项耗时的任务。
  • 主线程在预定义的时间段内等待任务完成。如果 a. 主线程必须继续。任务完成或 b.发生超时。

这是我使用 AutoResetEvent 对象的尝试:

using(var waitHandle = new AutoResetEvent(false)){
    var worker = new Thread(() =>
    {
        try
        {
            TimeConsumingTask();
            waitHandle.Set(); //throws System.ObjectDisposedException: Safe handle has been closed
        }
        catch (Exception e)
        {...}
    }) {IsBackground = true};
    worker.Start(); //start worker

    const int waitTimeInMs = 5000; 
    var signaled = waitHandle.WaitOne(waitTimeInMs);//block main thread here. 
    if (!signaled)
    { //if timed out
       worker.Interrupt();
    }
}

有一个明显的竞争条件,主线程等待超时并释放导致 ObjectDisposedException 异常的等待句柄对象。我有没有其他方法可以设置它,以便正确处理句柄并且不会导致异常?

【问题讨论】:

  • 为什么主线程在处理等待对象?它的存在是为了向/从线程发出信号 - 线程应该拥有它。
  • 这如何解决竞争条件?如果在主线程调用waitOne之前在工作线程中释放了waithandle,waitOne会抛出同样的异常。
  • 你能切换到Task吗?让许多事情变得更容易。

标签: c# multithreading waithandle


【解决方案1】:

当然,没有像样的方法可以做到这一点。请预先注意,您实际上是通过让线程狂奔而将自己描绘成那个角落,这没有什么特别好的。

但您关注的是小得多的问题。 Thread 类本身已经是一个资源消耗者,消耗 1 兆字节的 VM 和 5 个同步对象。但它没有 Dispose() 方法。这是一个大胆的设计,只是没有像样的方法来调用该方法。

Disposing 是可选的,当你不调用它时,不会发生任何戏剧性的事情。该课程得到了您的支持,它有一个终结器,可确保释放本机操作系统资源。哪个最终运行,只是没有你想要的那么快。

将此与设计胆子较小的类进行比较,Task 类有一个 Dispose() 方法。就像 Thread 一样,它几乎同样难以调用。 guidance from the .NET gurus 就是不要打扰。

这里也一样。

【讨论】:

  • 谢谢,这很有用。重新评论让线程疯狂运行,那里的最佳做法是什么?
  • 当然不会让他们狂奔。我不知道你为什么认为它很重要。如果线程没有在合理的时间内完成是异常的,那么您应该引发异常。这是勇敢的事情。
【解决方案2】:

等待句柄正在释放,因为您的使用范围调用了一个新线程并立即返回,导致等待句柄释放。

你应该做的是在你完成工作后显式调用 dispose 而不是你的 using 语句:

waitHandle.WaitOne(waitTimeInMs);
if (!signaled)
{ //if timed out
   worker.Interrupt();
}
waitHandle.Dispose();

【讨论】:

  • 如果 Dispose() 在 worker 有机会被中断之前在 waitHandle 上调用,Set() 仍然会抛出异常。竞争条件仍然存在显式的 dispose 调用。
猜你喜欢
  • 1970-01-01
  • 2014-08-31
  • 1970-01-01
  • 2013-04-07
  • 2016-01-31
  • 1970-01-01
  • 1970-01-01
  • 2017-10-24
  • 1970-01-01
相关资源
最近更新 更多