我们使用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;
}
Run Code Online (Sandbox Code Playgroud)
这样,调用cts.Cancel()将导致任务线程被阻塞,以防它被阻塞.但是,这导致了一个问题:我们不知道线程是否实际上得到了ThreadInterruptedException.我们可能会调用Thread.Interrupt()它,但线程将运行完成,任务将结束.在这种情况下,线程池线程将以ThreadInterruptedException的形式出现一个滴答声炸弹,当另一个任务在此线程上运行并尝试阻塞时,它将获得此异常.
一个Thread.ResetInterrupted()方法(类似于Thread.ResetAbort())在这里会有所帮助,但它似乎并不存在.我们可以使用以下内容:
try
{
someEvent.Wait(10);
}
catch (ThreadInterruptedException) {}
Run Code Online (Sandbox Code Playgroud)
吞下ThreadInterruptedException,但看起来很难看.
有人可以建议替代方案吗?在线程池线程上调用Thread.Interrupt是错误的吗?这似乎是取消任务的最简单方法:使用事件等的协作取消使用起来要麻烦得多,并且必须传播到我们从任务中使用的所有类中.