.Net Cancellable Task - APM异步超时机制扩展
概述
.NET基于委托的APM(Asynchronous Programming Model)模式通過BeginInvoke, EndInvoke, AsyncCallback,IAsyncResult的組合使用,讓程序員可以方便的進(jìn)行異步調(diào)用、異步回調(diào)和同步等待等操作。但.NET平臺還沒有為線程的中止(abort)提供安全可靠的機(jī)制,也許正是基于這個原因APM并沒有包含異步調(diào)用的超時機(jī)制,而是把這個可能引起爭議的工作交給使用者自己來把握。
作為APM模型的補(bǔ)充,本文通過CancellableTask類提供了一個異步調(diào)用超時機(jī)制。CancellableTask類的設(shè)計(jì)有兩個主要的考慮:
1.保持APM風(fēng)格,使用者依然可以使用熟悉的BeginInvoke, EndInvoke, IAsyncResult, AsyncCallback等;
2.提供基于Thread.Abort的默認(rèn)超時處理,同時支持用戶自定義cancel回調(diào)。
使用
CancellableTask的構(gòu)造函數(shù)包含workCallbak和cancelCallback(可選)兩參數(shù),分別對應(yīng)work回調(diào)和cancel回調(diào)。CancellableTask的BeginInvoke保持了APM的風(fēng)格,可以看作是增加了timeout參數(shù)(單位:ms)的擴(kuò)展版;而EndInvoke,AsyncCallback以及IAsyncResult的使用都和APM保持一致。Work委托產(chǎn)生的異常會在EndInvoke時拋出,同時若線程被超時中止,EndInvoke則會拋出ThreadAbortException異常。
下面是一段CancellableTask的使用示例:
?
class?Program{
????static?void?Main(string[]?args)
????{
????????//默認(rèn)超時直接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回調(diào)
????????{
????????????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;?}
}
實(shí)現(xiàn)
CancellableTask通過wrapper對workCallback進(jìn)行包裝。Wrapper內(nèi)部首先創(chuàng)建等待事件e,并通過ThreadPool.RegisterWaitForSingleObject注冊事件和WaitOrTimeout回調(diào),然后調(diào)用workCallback。若workCallback提前返回,調(diào)用e.Set(),ThreadPool會調(diào)用WaitOrTimeout回調(diào),isTimeout參數(shù)為false,不進(jìn)行處理;否則,當(dāng)workCallback超時未返回,ThreadPool會調(diào)用WaitOrTimeout回調(diào),isTimeout參數(shù)為true。WaitOrTimeout回調(diào)在isTimeout情況下,首先判斷是否有自定義cancel回調(diào),如果有則采用自定義回調(diào);否則,默認(rèn)情況下調(diào)用Thread.Abort終止work線程。下面是CancellableTask的實(shí)現(xiàn)細(xì)節(jié):
?
public?class?CancellableTask{
????public?delegate?object?WorkCallback(object?arg);
????public?delegate?void?CancelCallback(object?state);
????protected?class?TimeoutState
????{
????????internal?Thread?thread;
????????internal?object?state;
????????public?TimeoutState(Thread?thread,?object?state)
????????{
????????????this.thread?=?thread;
????????????this.state?=?state;
????????}
????}
????protected?WorkCallback?workCallback;
????protected?CancelCallback?cancelCallback;
????protected?WorkCallback?wrapper;
????public?CancellableTask(WorkCallback?workCallback)
????{
????????this.workCallback?=?workCallback;
????}
????public?CancellableTask(WorkCallback?workCallback,?CancelCallback?cancelCallback)
????{
????????this.workCallback?=?workCallback;
????????this.cancelCallback?=?cancelCallback;
????}
????public?IAsyncResult?BeginInvoke(object?arg,?AsyncCallback?asyncCallback,?object?state,?int?timeout)
????{
????????wrapper?=?delegate(object?argv)
????????{
????????????AutoResetEvent?e?=?new?AutoResetEvent(false);
????????????try
????????????{
????????????????TimeoutState?waitOrTimeoutState?=?new?TimeoutState(Thread.CurrentThread,?state);
????????????????ThreadPool.RegisterWaitForSingleObject(e,?WaitOrTimeout,?waitOrTimeoutState,?timeout,?true);
????????????????return?workCallback(argv);
????????????}
????????????finally
????????????{
????????????????e.Set();
????????????}
????????};
????????IAsyncResult?asyncResult?=?wrapper.BeginInvoke(arg,?asyncCallback,?state);
????????return?asyncResult;
????}
????public?object?EndInvoke(IAsyncResult?result)
????{
????????return?wrapper.EndInvoke(result);
????}
????protected?void?WaitOrTimeout(object?state,?bool?isTimeout)
????{
????????try
????????{
????????????if?(isTimeout)
????????????{
????????????????TimeoutState?waitOrTimeoutState?=?state?as?TimeoutState;
????????????????if?(null?!=?cancelCallback)
????????????????{
????????????????????cancelCallback(waitOrTimeoutState.state);
????????????????}
????????????????else
????????????????{
????????????????????waitOrTimeoutState.thread.Abort();
????????????????}
????????????}
????????}
????????catch?{?}
????}
}
總結(jié)
本文為.NET APM模型提供了異步超時機(jī)制擴(kuò)展,一方面保持了APM編程風(fēng)格,另一方面支持用戶自定義cancel回調(diào)。需要注意的是,默認(rèn)的cancel方式Thread.Abort的安全性問題,使用時應(yīng)注意資源釋放等。
作者
http://www.cnblogs.com/weidagang2046/,歡迎就線程問題交流探討。
轉(zhuǎn)載于:https://www.cnblogs.com/weidagang2046/archive/2009/02/19/1394050.html
總結(jié)
以上是生活随笔為你收集整理的.Net Cancellable Task - APM异步超时机制扩展的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C# 使用 Lotus notes 公共
- 下一篇: 矮生百慕大