zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    虚拟环境- virtualenvwrapper
    数据库可视化工具--DBeaver
    关于数据库 SQL 语句性能优化的52 条 策略。
    软件安全测试点以及测试方法
    常用功能-添加、修改功能测试点
    这些自动化测试框架知识你还不知道?
    Postman接口功能测试介绍
    python+SMTP发送邮件测试报告
    数据库经典查询语句与练习题
    Selenium 功能总结大集合
  • 原文地址:https://www.cnblogs.com/jasongrass/p/11252352.html
Copyright © 2011-2022 走看看