温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

C#中,函数运行超时的功能的实现

发布时间:2020-06-15 11:45:26 来源:网络 阅读:5882 作者:cnn237111 栏目:编程语言

主要使用BeginInvoke方法和ManualResetEvent类来实现。

BeginInvoke使得函数在线程池上异步运行,运行完成后,调用回调函数。

ManualResetEvent用于同步阻塞。

设计思想如下:

当函数在线程池中的某一线程上异步的运行的时候,ManualResetEvent阻塞当前线程,等待若干时间。

在等候期间,如果异步函数运行完毕,会对ManualResetEvent设置一个信号,使得阻塞的线程得以继续运行下去。

如果等候超时了,则阻塞的线程也会取消阻塞,继续运行下去,但是不再理会回调的函数。(即使回调函数仍然被调用),事实上,BeginInvoke创建的线程都是后台线程,这种线程一但所有的前台线程都退出后(其中主线程就是一个前台线程),不管后台线程是否执行完毕,都会结束线程,并退出。因此如果阻塞的主线程完全运行完毕退出,那么异步运行的线程也会退出,无论是否运行完毕。

语句isGetSignal = manu.WaitOne(timeout);就是阻塞当前线程一段时间。

该语句阻塞期间,不会对isGetSignal赋值,直到阻塞取消后,才会返回一个值给isGetSignal。

当阻塞是因为收到信号而取消的,得到的值是true。

当阻塞是因为超时而取消的,得到的值是false。

整个流程如下:

C#中,函数运行超时的功能的实现

把这些代码逻辑封装成一个类。

这个类就接受一个委托和一个超时时间作为构造函数。

把这个委托和 ManualResetEvent .Set();语句写在一个方法体内,CombineActionAndManuset,因此CombineActionAndManuset的调用就是实现了方法运行完毕后,设置取消阻塞信号。

封装后的代码:

  1. public class FuncTimeout  
  2.    {  
  3.        /// <summary>  
  4.        /// 信号量  
  5.        /// </summary>  
  6.        public ManualResetEvent manu = new ManualResetEvent(false);  
  7.        /// <summary>  
  8.        /// 是否接受到信号  
  9.        /// </summary>  
  10.  
  11.        public bool isGetSignal;  
  12.        /// <summary>  
  13.        /// 设置超时时间  
  14.        /// </summary>  
  15.        public int timeout;  
  16.        /// <summary>  
  17.        /// 要调用的方法的一个委托  
  18.        /// </summary>  
  19.        public Action<int> FunctionNeedRun;  
  20.  
  21.        /// <summary>  
  22.        /// 构造函数,传入超时的时间以及运行的方法  
  23.        /// </summary>  
  24.        /// <param name="_action"></param>  
  25.        /// <param name="_timeout"></param>  
  26.        public FuncTimeout(Action<int> _action, int _timeout)  
  27.        {  
  28.            FunctionNeedRun = _action;  
  29.            timeout = _timeout;  
  30.        }  
  31.  
  32.        /// <summary>  
  33.        /// 回调函数  
  34.        /// </summary>  
  35.        /// <param name="ar"></param>  
  36.        public void MyAsyncCallback(IAsyncResult ar)  
  37.        {  
  38.            //isGetSignal为false,表示异步方法其实已经超出设置的时间,此时不再需要执行回调方法。  
  39.            if (isGetSignal == false)  
  40.            {  
  41.                Console.WriteLine("放弃执行回调函数");  
  42.                Thread.CurrentThread.Abort();  
  43.            }  
  44.            else 
  45.            {  
  46.                Console.WriteLine("调用回调函数");  
  47.            }  
  48.        }  
  49.  
  50.        /// <summary>  
  51.        /// 调用函数  
  52.        /// </summary>  
  53.        /// <param name="param1"></param>  
  54.        public void doAction(int param1)  
  55.        {  
  56.            Action<int> WhatTodo = CombineActionAndManuset;  
  57.            //通过BeginInvoke方法,在线程池上异步的执行方法。  
  58.            var r=WhatTodo.BeginInvoke(param1, MyAsyncCallback, null);  
  59.            //设置阻塞,如果上述的BeginInvoke方法在timeout之前运行完毕,则manu会收到信号。此时isGetSignal为true。  
  60.            //如果timeout时间内,还未收到信号,即异步方法还未运行完毕,则isGetSignal为false。  
  61.            isGetSignal = manu.WaitOne(timeout);  
  62.              
  63.            if (isGetSignal == true)  
  64.            {  
  65.                Console.WriteLine("函数运行完毕,收到设置信号,异步执行未超时");  
  66.            }  
  67.            else 
  68.            {  
  69.                Console.WriteLine("没有收到设置信号,异步执行超时");  
  70.            }  
  71.        }  
  72.  
  73.        /// <summary>  
  74.        /// 把要传进来的方法,和 manu.Set()的方法合并到一个方法体。  
  75.        /// action方法运行完毕后,设置信号量,以取消阻塞。  
  76.        /// </summary>  
  77.        /// <param name="num"></param>  
  78.        public void CombineActionAndManuset(int num)  
  79.        {  
  80.            FunctionNeedRun(num);  
  81.            manu.Set();  
  82.        }  
  83.    }  

测试代码:

 

  1. class Program  
  2.     {  
  3.         static void Main(string[] args)  
  4.         {  
  5.             FuncTimeout ft = new FuncTimeout(dosth, 3000);  
  6.             ft.doAction(6);  
  7.         }  
  8.  
  9.        static void dosth(int num)  
  10.         {  
  11.             for (int i = 0; i < num; i++)  
  12.             {  
  13.                 Thread.Sleep(500);  
  14.                 Console.Write(i);  
  15.             }  
  16.         }  
  17.     } 

 

当超时时间设置为5s的时候,方法未超时

C#中,函数运行超时的功能的实现

当超时时间设置为1s的时候,方法超时

C#中,函数运行超时的功能的实现

附件:http://down.51cto.com/data/2361797
向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI