Thread 另类用法,如何执行一段可能死锁/卡死/死循环的代码
场景与需求
需要执行一段第三方的代码,这段代码可能死锁/卡死/死循环,在超时之后,如果没有结束,则认为任务执行失败,退出执行。
实现方案1:使用 Task 超时
实现方法参考:
https://www.cnblogs.com/jasongrass/p/10354727.html
但这里有一个问题,既然被执行的任务可能死锁,即可能永远不会结束(除非进程退出),如果使用上述方式,将有一个线程始终被占用,无法释放,这是很浪费资源的。
实现方案2:使用 Thread
基本思路:
执行任务,超时则将任务所在 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://www.cnblogs.com/jasongrass/p/11252352.html
Thread 另类用法,如何执行一段可能死锁/卡死/死循环的代码的更多相关文章
- 研究 Javascript的&&和||的另类用法
这篇文章主要介绍了Javascript的&&和||的另类用法,需要的朋友可以参考下 最近也没什么心思写文章了,感觉总有忙不完的事情,呵. 不过这些天又开始研究起 Titanium 来, ...
- Javascript的&&和||的另类用法
Javascript的&&和||的另类用法. 又开始研究起 Titanium 来,发现其官方出品的MVC框架(Alloy)还是挺不错的,刚开始苦于没有好的代码来学习,文档又少,所以一直 ...
- C#实现不影响当前线程情况下间隔一定的时间执行一段代码
大家知道C#间隔一定时间去执行一段代码,常用的有 1. Thread.Sleep(多少毫秒); 2. 使用Timer控件间隔一定的时间,设置执行一次 以上两种方法,实现起来不难,弊端在于会阻塞当前线程 ...
- Python装饰器的另类用法
之前有比较系统介绍过Python的装饰器(请查阅<详解Python装饰器>),本文算是一个补充.今天我们一起探讨一下装饰器的另类用法. 语法回顾 开始之前我们再将Python装饰器的语法回 ...
- 写在Github被微软收购之际 - Github的那些另类用法
这几天朋友圈被微软75亿美元收购Github的新闻刷屏了.Jerry也来贡献一篇和Github相关的文章. 这篇文章包含了Jerry平时对于Github的一些另类用法.目录如下: 1. 部署HTML应 ...
- Rpm另类用法加固Linux安全
Rpm另类用法加固Linux安全 RPM是Red Hat Package Manager的缩写即Red Hat软件管理器.它是一个开放的包管理软件,由Red Hat公司所开发和维护,可以在Red ...
- 关于ScheduledExecutorService执行一段时间之后就不执行的问题
在项目中使用java的定时任务时,有的时候执行一段时间后没任何反应了.这里有篇文章说了这个问题.猛击下面的链接. http://blog.163.com/scuqifuguang@126/blog/s ...
- Unity 延迟执行一段代码的较为优雅的方式
在Unity中,延时执行一段代码或者一个方法或者几个方法的情况非常普遍. 一般会用到Invoke和InvokeRepeating方法.顾名思义,第一个是执行一次,第二个是重复执行. 看下定义: voi ...
- [转]Unity 延迟执行一段代码的较为优雅的方式
Unity中,延时执行一段代码或者一个方法或者几个方法的情况非常普遍. 一般会用到Invoke和InvokeRepeating方法.顾名思义,第一个是执行一次,第二个是重复执行. 看下定义: void ...
随机推荐
- PHP+Mysql查询上一篇和下一篇文章实例
简单的PHP+Mysql查询上一篇和下一篇文章实例,并输出上一篇和下一篇文章的标题和链接,适合新手学习 获取当前浏览文章id: $id = isset($_GET['id']) > 0 ? in ...
- js动态设置padding-top遇到的坑
我想通过js动态设置元素padding-top的百分比值:以下几种都是无法设置成功的: // setAttribute设置padding-top并且转换为百分比 imageBox.setAttribu ...
- 跳转常规 -- 为什么不要使用404、500等http状态码作为业务代码响应
不要使用HTTP状态码作为业务代码响应 HTTP状态码 是指浏览器访问网址,成功或异常时浏览器或服务器告知用户的代码数字,它指的是网络或服务器的状态,有着不同的含义. 参加MDN.Java Api,常 ...
- Apache配置https
Apache配置https 之前一直用的是Tomcat,今天突然接到任务要给Apache配置https证书,因为小程序要用.下面把过程列出来以备后续查看. 1.首先你得有ssl证书,没有的可以去购买, ...
- python函数修饰符@的使用
python函数修饰符@的作用是为现有函数增加额外的功能,常用于插入日志.性能测试.事务处理等等. 创建函数修饰符的规则:(1)修饰符是一个函数(2)修饰符取被修饰函数为参数(3)修饰符返回一个新函数 ...
- [Go] 利用有缓存channel控制同时并发的数量
如果有一个大循环,里面每一个都开启groutine,那么瞬间就会开启非常多的groutine,要解决这个问题就要用channel的阻塞特性来解决 package main import "t ...
- java下实现压缩数据存取
使用Apache Commons Compress实现压缩数据存取,支持格式有XZ,7z,tar,zip,jar,bzip2,gzip等. 例子在 https://commons.apache.org ...
- Java重定向标准输入/输出
在System类中提供了三个重定向标准输入/输出的方法static void setErr(PrintStream err) 重定向“标准”错误输出流static void setIn(InputSt ...
- socket 与 websocket的区别
区别: socket并不是一个协议,而是抽象出来的一层,应用于应用层和传输控制层之间的一组接口, socket是传输控制层协议,websocket是应用层协议 websocket是什么样的协议,具有什 ...
- Tensorflow之多元线性回归问题(以波士顿房价预测为例)
一.根据波士顿房价信息进行预测,多元线性回归+特征数据归一化 #读取数据 %matplotlib notebook import tensorflow as tf import matplotlib. ...