Welcome

首页 / 软件开发 / .NET编程技术 / .Net Cancellable Task - APM异步超时机制扩展

.Net Cancellable Task - APM异步超时机制扩展2011-11-14概述

.NET基于委托的APM(Asynchronous Programming Model)模型通过BeginInvoke, EndInvoke, AsyncCallback,IAsyncResult的组合使用,让程序员可以方便的进行异步调用、异步回调和同步等待等操作。但.NET平台还没有为线程的中止(abort)提供安全可靠的机制,也许正是基于这个原因APM并没有包含异步调用的超时机制,而是把这个可能引起争议的工作交给使用者自己来把握。

作为APM模型的补充,本文通过CancellableTask类提供了一个异步调用超时机制。CancellableTask类的设计有两个主要的考虑:

1.保持APM风格,使用者依然可以使用熟悉的BeginInvoke, EndInvoke, IAsyncResult, AsyncCallback等;

2.提供基于Thread.Abort的默认超时处理,同时支持用户自定义cancel回调。

使用

CancellableTask的构造函数包含workCallbak和cancelCallback(可选)两参数,分别对应work回调和cancel回调。CancellableTask的BeginInvoke保持了APM的风格,可以看作是增加了timeout参数(单位:ms)的扩展版;而EndInvoke,AsyncCallback以及IAsyncResult的使用都和APM保持一致。Work委托产生的异常会在EndInvoke时抛出,同时若线程被超时中止,EndInvoke则会抛出ThreadAbortException异常。

下面是一段CancellableTask的使用示例:

class Program{static void Main(string[] args){//默认超时直接abort线程{Console.WriteLine("[case 1]");CancellableTask cancellableTask = new CancellableTask(Work);State arg = new State { Loop = 20, Stop = false };IAsyncResult asyncResult = cancellableTask.BeginInvoke(arg, (ar => Console.WriteLine("Async Callback")), null, 10 * 1000);asyncResult.AsyncWaitHandle.WaitOne();try{object r = cancellableTask.EndInvoke(asyncResult);Console.WriteLine("return " + r);}catch (ThreadAbortException){Console.WriteLine("Thread Aborted");}catch (Exception exp){Console.WriteLine(exp.ToString());}}//自定义Cancel回调{Console.WriteLine(Environment.NewLine + "[case 2]");CancellableTask cancellableTask = new CancellableTask(Work, Cancel);State arg = new State { Loop = 20, Stop = false };IAsyncResult asyncResult = cancellableTask.BeginInvoke(arg,(ar =>{try{object r = cancellableTask.EndInvoke(ar);Console.WriteLine("return " + r);}catch (ThreadAbortException){Console.WriteLine("Thread Aborted");}catch (Exception exp){Console.WriteLine(exp.ToString());}}),arg,10 * 1000);}Console.ReadLine();}static object Work(object arg){State state = arg as State;int i;for (i = 0; i < state.Loop; i++){if (state.Stop) break;Console.WriteLine(i);Thread.Sleep(1000);}return i;}static void Cancel(object state){State st = state as State;st.Stop = true;}}internal class State{public int Loop { get; set; }public bool Stop { get; set; }}