1

根据文档,.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 异常的等待句柄对象。有没有其他方法可以设置它以便正确处理句柄并且不会导致异常?

4

2 回答 2

4

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

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

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

将此与设计不够大胆的类进行比较,Task 类有一个 Dispose() 方法。就像 Thread 一样,它几乎同样难以调用。.NET 大师的指导就是不要打扰。

同样在这里。

于 2014-04-13T09:42:29.840 回答
0

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

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

waitHandle.WaitOne(waitTimeInMs);
if (!signaled)
{ //if timed out
   worker.Interrupt();
}
waitHandle.Dispose();
于 2014-04-13T07:35:43.090 回答