场景与需求

需要执行一段第三方的代码,这段代码可能死锁/卡死/死循环,在超时之后,如果没有结束,则认为任务执行失败,退出执行。

实现方案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 另类用法,如何执行一段可能死锁/卡死/死循环的代码的更多相关文章

  1. 研究 Javascript的&&和||的另类用法

    这篇文章主要介绍了Javascript的&&和||的另类用法,需要的朋友可以参考下 最近也没什么心思写文章了,感觉总有忙不完的事情,呵. 不过这些天又开始研究起 Titanium 来, ...

  2. Javascript的&&和||的另类用法

    Javascript的&&和||的另类用法. 又开始研究起 Titanium 来,发现其官方出品的MVC框架(Alloy)还是挺不错的,刚开始苦于没有好的代码来学习,文档又少,所以一直 ...

  3. C#实现不影响当前线程情况下间隔一定的时间执行一段代码

    大家知道C#间隔一定时间去执行一段代码,常用的有 1. Thread.Sleep(多少毫秒); 2. 使用Timer控件间隔一定的时间,设置执行一次 以上两种方法,实现起来不难,弊端在于会阻塞当前线程 ...

  4. Python装饰器的另类用法

    之前有比较系统介绍过Python的装饰器(请查阅<详解Python装饰器>),本文算是一个补充.今天我们一起探讨一下装饰器的另类用法. 语法回顾 开始之前我们再将Python装饰器的语法回 ...

  5. 写在Github被微软收购之际 - Github的那些另类用法

    这几天朋友圈被微软75亿美元收购Github的新闻刷屏了.Jerry也来贡献一篇和Github相关的文章. 这篇文章包含了Jerry平时对于Github的一些另类用法.目录如下: 1. 部署HTML应 ...

  6. Rpm另类用法加固Linux安全

    Rpm另类用法加固Linux安全   RPM是Red Hat Package Manager的缩写即Red Hat软件管理器.它是一个开放的包管理软件,由Red Hat公司所开发和维护,可以在Red ...

  7. 关于ScheduledExecutorService执行一段时间之后就不执行的问题

    在项目中使用java的定时任务时,有的时候执行一段时间后没任何反应了.这里有篇文章说了这个问题.猛击下面的链接. http://blog.163.com/scuqifuguang@126/blog/s ...

  8. Unity 延迟执行一段代码的较为优雅的方式

    在Unity中,延时执行一段代码或者一个方法或者几个方法的情况非常普遍. 一般会用到Invoke和InvokeRepeating方法.顾名思义,第一个是执行一次,第二个是重复执行. 看下定义: voi ...

  9. [转]Unity 延迟执行一段代码的较为优雅的方式

    Unity中,延时执行一段代码或者一个方法或者几个方法的情况非常普遍. 一般会用到Invoke和InvokeRepeating方法.顾名思义,第一个是执行一次,第二个是重复执行. 看下定义: void ...

随机推荐

  1. json字符串转为php数组,使用随机字符串生成订单号(学生笔记)

    //提交订单 function add_order(){ session_start(); // var_dump($_SESSION); // die(); // session_destroy() ...

  2. CSS基本选择器是什么?基本选择器是如何工作

    基本选择器介绍 基本选择器又分为六种使用方式:如.通用选择器.标签选择器.类选择器.Id选择器.结合元素选择器.多类选择器. 基本选择器使用说明表. 选择器 语法格式 含义 举例 通用选择器 *{属性 ...

  3. Github使用总结(添加ssh-key,新建仓库,添加协作者) 转

    http://jingyan.baidu.com/article/ab0b5630936ab6c15afa7d1c.html https://help.github.com/articles/gene ...

  4. gradle 参数配置监听

    说明 gradle提供了对project状态配置监听的接口回调,以方便我们来配置一些Project的配置属性,监听主要分为两大类,一种是通过project进行 回调,一种是通过gradle进行回调,作 ...

  5. Pwn-level2

    题目地址 https://dn.jarvisoj.com/challengefiles/level2.54931449c557d0551c4fc2a10f4778a1 先看一下文件的属性   32位 ...

  6. win10打印所有进程

    #include <map> #include <iostream> #include <string> #include <windows.h> #i ...

  7. selenium定位元素的八种方法

    web driver提供了八种元素定位的方法: id, name, class name, tag name, link text, partial link text, xpath, css sel ...

  8. 更换github账号后,push被旧账号阻止

    和网上多数的教程不同,我是需要直接更换账号.切换后push一直被阻止.解决后记录下办法 remote: Permission to new-name/practice.git denied to ol ...

  9. linux 下安装 python ngix 项目发布流程

    1.安装python #1.安装python3.7所需要的依赖包yum -y groupinstall "Development tools"yum -y install zlib ...

  10. Java的 StringBuffer 和 StringBuilder 类

    https://www.runoob.com/java/java-stringbuffer.html 返回值是它本身的类, 所以可以链式调用! 总结就是可以直接在对象上使用 , 可以链式使用, buf ...