前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >Thread 另类用法,如何执行一段可能死锁/卡死/死循环的代码

Thread 另类用法,如何执行一段可能死锁/卡死/死循环的代码

作者头像
jgrass
发布2024-12-25 16:10:01
发布2024-12-25 16:10:01
7100
代码可运行
举报
文章被收录于专栏:蔻丁杂记蔻丁杂记
运行总次数:0
代码可运行

场景与需求

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

实现方案1:使用 Task 超时

实现方法参考:实现可设置超时的 Task

但这里有一个问题,既然被执行的任务可能死锁,即可能永远不会结束(除非进程退出),如果使用上述方式,将有一个线程始终被占用,无法释放,这是很浪费资源的。

实现方案2:使用 Thread

基本思路:

执行任务,超时则将任务所在 Thread 终止(Abord)。

基本代码(还有需要完善,如支持返回值等。)

代码语言:javascript
代码运行次数:0
复制
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();        }    }}

具体调用:

代码语言:javascript
代码运行次数:0
复制
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 国际」 许可协议进行许可,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019年7月26日 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 场景与需求
  • 实现方案1:使用 Task 超时
  • 实现方案2:使用 Thread
  • 注意点
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档