Dispose WaitHandle用于基本线程同步

本文关键字:线程 同步 WaitHandle 用于 Dispose | 更新日期: 2023-09-27 17:58:01

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

Dispose WaitHandle用于基本线程同步

当然,没有什么像样的方法可以做到这一点。请注意,你把自己画到了那个角落,基本上留下了一条疯狂的线索,这并没有什么特别好的。

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

处置是可选的,当你不调用它时,不会发生什么戏剧性的事情。这个类已经支持你了,它有一个终结器,可以确保释放本机操作系统资源。哪个最终会运行,只是没有你想要的那么快。

与设计不那么大胆的类相比,Task类有一个Dispose()方法。和Thread一样,这几乎同样难以调用。来自.NET大师的指导就是不要麻烦。

这里也是。

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

你应该做的是在你完成工作后明确地调用dispose,而不是你的using语句:

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