需要执行一段第三方的代码,这段代码可能死锁/卡死/死循环,在超时之后,如果没有结束,则认为任务执行失败,退出执行。
实现方法参考:实现可设置超时的 Task
但这里有一个问题,既然被执行的任务可能死锁,即可能永远不会结束(除非进程退出),如果使用上述方式,将有一个线程始终被占用,无法释放,这是很浪费资源的。
基本思路:
执行任务,超时则将任务所在 Thread 终止(Abord)。
基本代码(还有需要完善,如支持返回值等。)
using System;using System.Threading;using System.Threading.Task;
public class ForceCancellationAction{ private CancellationTokenSource CancellationTokenSource { get; }
private readonly Action _action; private readonly TimeSpan _timeout;
public Exception BusinessException { get; private set; }
public bool IsFinishedCauseTimeout { get; private set; }
public ForceCancellationAction(Action action, TimeSpan timeout) { _action = action; _timeout = timeout; CancellationTokenSource = new CancellationTokenSource(); }
/// <summary> /// 执行指定的任务,如果任务执行超时,任务将被强制终止。 /// </summary> /// <returns></returns> public Task Do() { Thread thread = new Thread(TargetThreadAction) { IsBackground = true };
return Task.Run(async () => { try { thread.Start(); try { await Task.Delay(_timeout, CancellationTokenSource.Token);
// 计时到,强制终止目标线程 thread.Abort(); } catch (TaskCanceledException) { // 目标线程中的工作正确结束 } } catch (Exception ex) { Log.Error("[ForceCancellationAction]", ex); }
}); }
private void TargetThreadAction() { try { _action(); } catch (ThreadAbortException) { // 计时到,线程被强制终止。 IsFinishedCauseTimeout = true;
// ThreadAbortException 会被重新抛出,所以,需要调用 Thread.ResetAbort(); 重启线程。 // [ThreadAbortException Class (System.Threading) | Microsoft Docs](https://docs.microsoft.com/zh-cn/dotnet/api/system.threading.threadabortexception?view=netframework-4.8 ) Thread.ResetAbort(); } catch (Exception ex) { Log.Error("[ForceCancellationAction]", ex);
// 目标执行代码抛了业务异常 BusinessException = ex; } finally { // 目标线程执行完毕,取消等待计时。 CancellationTokenSource.Cancel(); } }}
具体调用:
var forceAction = new ForceCancellationAction(() =>{ // 可能死锁/卡死/死循环的代码}, TimeSpan.FromSeconds(2));await forceAction.Do();
这样,在被执行任务出现意外卡死时,可以强制杀死线程。
需要注意的是,ThreadAbortException 捕获后,需要恢复线程,让其“自然”结束,因为这个异常是接不住的,会一直向上抛出,除非恢复线程。
参考:
ThreadAbortException Class (System.Threading) | Microsoft Docs
原文链接: https://cloud.tencent.com/developer/article/2481451
本作品采用 「署名 4.0 国际」 许可协议进行许可,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。