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异常的等待句柄对象。有没有其他方法可以设置它,以便正确处理句柄,而不会导致异常?
当然,没有什么像样的方法可以做到这一点。请注意,你把自己画到了那个角落,基本上留下了一条疯狂的线索,这并没有什么特别好的。
但你关注的是一个小得多的问题。Thread类本身已经是一个资源占用者,消耗了一兆字节的VM和五个同步对象。但它没有Dispose()方法。这是一个勇敢的设计,只是没有一个像样的方法来称呼这种方法。
处置是可选的,当你不调用它时,不会发生什么戏剧性的事情。这个类已经支持你了,它有一个终结器,可以确保释放本机操作系统资源。哪个最终会运行,只是没有你想要的那么快。
与设计不那么大胆的类相比,Task类有一个Dispose()方法。和Thread一样,这几乎同样难以调用。来自.NET大师的指导就是不要麻烦。
这里也是。
等待句柄正在处理,因为您的使用范围调用了一个新线程并立即返回,从而导致等待句柄被处理。
你应该做的是在你完成工作后明确地调用dispose,而不是你的using语句:
waitHandle.WaitOne(waitTimeInMs);
if (!signaled)
{ //if timed out
worker.Interrupt();
}
waitHandle.Dispose();