当前位置:编程学习 > C#/ASP.NET >>

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

主要使用BeginInvoke方法和ManualResetEvent类来实现。
BeginInvoke使得函数在线程池上异步运行,运行完成后,调用回调函数。
ManualResetEvent用于同步阻塞。
设计思想如下:
当函数在线程池中的某一线程上异步的运行的时候,ManualResetEvent阻塞当前线程,等待若干时间。
在等候期间,如果异步函数运行完毕,会对ManualResetEvent设置一个信号,使得阻塞的线程得以继续运行下去。
如果等候超时了,则阻塞的线程也会取消阻塞,继续运行下去,但是不再理会回调的函数。(即使回调函数仍然被调用),事实上,BeginInvoke创建的线程都是后台线程,这种线程一但所有的前台线程都退出后(其中主线程就是一个前台线程),不管后台线程是否执行完毕,都会结束线程,并退出。因此如果阻塞的主线程完全运行完毕退出,那么异步运行的线程也会退出,无论是否运行完毕。
语句isGetSignal = manu.WaitOne(timeout);就是阻塞当前线程一段时间。
该语句阻塞期间,不会对isGetSignal赋值,直到阻塞取消后,才会返回一个值给isGetSignal。
当阻塞是因为收到信号而取消的,得到的值是true。
当阻塞是因为超时而取消的,得到的值是false。
整个流程如下:
clipboard

把这些代码逻辑封装成一个类。
这个类就接受一个委托和一个超时时间作为构造函数。
把这个委托和 ManualResetEvent .Set();语句写在一个方法体内,CombineActionAndManuset,因此CombineActionAndManuset的调用就是实现了方法运行完毕后,设置取消阻塞信号。
封装后的代码:
public class FuncTimeout 
   { 
       /// <summary> 
       /// 信号量 
       /// </summary> 
       public ManualResetEvent manu = new ManualResetEvent(false); 
       /// <summary> 
       /// 是否接受到信号 
       /// </summary> 
 
       public bool isGetSignal; 
       /// <summary> 
       /// 设置超时时间 
       /// </summary> 
       public int timeout; 
       /// <summary> 
       /// 要调用的方法的一个委托 
       /// </summary> 
       public Action<int> FunctionNeedRun; 
 
       /// <summary> 
       /// 构造函数,传入超时的时间以及运行的方法 
       /// </summary> 
       /// <param name="_action"></param> 
       /// <param name="_timeout"></param> 
       public FuncTimeout(Action<int> _action, int _timeout) 
       { 
           FunctionNeedRun = _action; 
           timeout = _timeout; 
       } 
 
       /// <summary> 
       /// 回调函数 
       /// </summary> 
       /// <param name="ar"></param> 
       public void MyAsyncCallback(IAsyncResult ar) 
       { 
           //isGetSignal为false,表示异步方法其实已经超出设置的时间,此时不再需要执行回调方法。 
           if (isGetSignal == false) 
           { 
               Console.WriteLine("放弃执行回调函数"); 
               Thread.CurrentThread.Abort(); 
           } 
           else
           { 
               Console.WriteLine("调用回调函数"); 
           } 
       } 
 
       /// <summary> 
       /// 调用函数 
       /// </summary> 
       /// <param name="param1"></param> 
       public void doAction(int param1) 
       { 
           Action<int> WhatTodo = CombineActionAndManuset; 
           //通过BeginInvoke方法,在线程池上异步的执行方法。 
           var r=WhatTodo.BeginInvoke(param1, MyAsyncCallback, null); 
           //设置阻塞,如果上述的BeginInvoke方法在timeout之前运行完毕,则manu会收到信号。此时isGetSignal为true。 
           //如果timeout时间内,还未收到信号,即异步方法还未运行完毕,则isGetSignal为false。 
           isGetSignal = manu.WaitOne(timeout); 
            
           if (isGetSignal == true) 
           { 
               Console.WriteLine("函数运行完毕,收到设置信号,异步执行未超时"); 
           } 
           else
           { 
               Console.WriteLine("没有收到设置信号,异步执行超时"); 
           } 
       } 
 
       /// <summary> 
       /// 把要传进来的方法,和 manu.Set()的方法合并到一个方法体。 
       /// action方法运行完毕后,设置信号量,以取消阻塞。 
       /// </summary> 
       /// <param name="num"></param> 
       public void CombineActionAndManuset(int num) 
       { 
           FunctionNeedRun(num); 
      &nbs

补充:软件开发 , C# ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,