【发布时间】:2012-08-12 18:01:01
【问题描述】:
我们正在使用 TPL 将长时间运行的任务排入线程池。 有些任务可能会阻塞一段时间,所以我们使用以下模式来取消它们:
private void RunAction(Action action, CancellationTokenSourceWithException cts)
{
try
{
s_logger.Info("Starting action on thread ID: {0}", Utils.GetCurrentNativeThreadId());
Thread taskThread = Thread.CurrentThread;
cts.Token.Register(() => InterruptTask(taskThread));
s_logger.Info("Running next action");
action();
}
catch (Exception e)
{
cts.Cancel(e);
throw;
}
这样,调用cts.Cancel()会导致任务线程被中断,以防它被阻塞。
然而,这导致了一个问题:我们不知道线程是否真的得到了 ThreadInterruptedException。有可能我们在它上面调用Thread.Interrupt(),但是线程将运行到完成并且任务将简单地结束。在这种情况下,线程池线程会有一个 ThreadInterruptedException 形式的定时炸弹,当另一个任务在这个线程上运行并试图阻塞时,它就会得到这个异常。
Thread.ResetInterrupted() 方法(类似于Thread.ResetAbort())在这里会有所帮助,但它似乎不存在。我们可以使用类似下面的东西:
try
{
someEvent.Wait(10);
}
catch (ThreadInterruptedException) {}
要吞掉ThreadInterruptedException,但是看起来很难看。
任何人都可以提出替代方案吗?我们在线程池线程上调用 Thread.Interrupt 是错误的吗?这似乎是取消任务的最简单方法:使用事件等的协作取消使用起来要麻烦得多,并且必须从任务传播到我们使用的所有类中。
【问题讨论】: