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

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

ManualResetEvent用于同步阻塞。

设计思想如下:

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

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

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

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

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

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

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

整个流程如下:

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

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

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

封装后的代码:

publicclassFuncTimeout { ///<summary> ///信号量 ///</summary> publicManualResetEventmanu=newManualResetEvent(false); ///<summary> ///是否接受到信号 ///</summary> publicboolisGetSignal; ///<summary> ///设置超时时间 ///</summary> publicinttimeout; ///<summary> ///要调用的方法的一个委托 ///</summary> publicAction<int>FunctionNeedRun; ///<summary> ///构造函数,传入超时的时间以及运行的方法 ///</summary> ///<paramname="_action"></param> ///<paramname="_timeout"></param> publicFuncTimeout(Action<int>_action,int_timeout) { FunctionNeedRun=_action; timeout=_timeout; } ///<summary> ///回调函数 ///</summary> ///<paramname="ar"></param> publicvoidMyAsyncCallback(IAsyncResultar) { //isGetSignal为false,表示异步方法其实已经超出设置的时间,此时不再需要执行回调方法。 if(isGetSignal==false) { Console.WriteLine("放弃执行回调函数"); Thread.CurrentThread.Abort(); } else{ Console.WriteLine("调用回调函数"); } } ///<summary> ///调用函数 ///</summary> ///<paramname="param1"></param> publicvoiddoAction(intparam1) { Action<int>WhatTodo=CombineActionAndManuset; //通过BeginInvoke方法,在线程池上异步的执行方法。 varr=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> ///<paramname="num"></param> publicvoidCombineActionAndManuset(intnum) { FunctionNeedRun(num); manu.Set(); } }

测试代码:

classProgram { staticvoidMain(string[]args) { FuncTimeoutft=newFuncTimeout(dosth,3000); ft.doAction(6); } staticvoiddosth(intnum) { for(inti=0;i<num;i++) { Thread.Sleep(500); Console.Write(i); } } }

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

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

附件:http://down.51cto.com/data/2361797