假如要在一個線程中異步執行一個方法,則先創建一個該方法的委托類型,然后CLR會自動為該委托類型定義一個BeginInvoke方法和EndInvoke方法,我們就靠這兩個方法異步調用委托類型指向的方法(這句話有點繞口,呵呵)
BeginInvoke這個方法用於啟動異步調用,該方法具有和要異步執行的方法具有相同的參數列表,只不過又多加了兩個參數,多加的那兩個參數的作用在后面介紹。執行BeginInvoke方法后,將立即返回一個IAsyncResult,用於監視被調用方法執行的進度。
EndInvoke這個方法用於得到異步調用的結果,調用BeginInvoke方法后隨時可以調用EndInvoke方法,假如異步調用還沒有完成,EndInvoke會阻塞到異步調用執行完畢,EndInvoke的參數包括被調用方法的out和ref參數,還有在調用BeginInvoke方法時得到的那個IAsyncResult(好像就是一個哈希表的key,可以靠這個key去得到相應的線程,這樣就可以處理多線程而不至於混亂了)
第一種方法:使用BeginInvoke方法后,主線程去執行一些操作,然后再使用EndInvoke方法等待被調用方法完成,以下是示例代碼
using System; using System.Collections.Generic; using System.Text; using System.Threading; namespace sample { class AsyncDemo // 我定義了一個演示的類,里面有一個測試方法TestMethod 其實完全可以把這個TestMethod寫到Main()函數的同一個類中,只不過寫成static方法即可 { public string TestMethod(int callDuration, out int threadid) { Console.WriteLine("Test Method begins"); Thread.Sleep(callDuration);//睡眠callDuration指定的毫秒 threadid = AppDomain.GetCurrentThreadId();//獲取當前線程的id return "MyCallTime was" + callDuration.ToString();//返回當前線程睡眠的時間 } } public delegate string AsyncDelegate(int callDuration, out int threadid); //創建一個AsyncDemo類中TestMethod方法相同簽名的委托類型 class Program { static void Main(string[] args) { int threadID; AsyncDemo ad = new AsyncDemo();//聲明一個AsyncDemo類型的對象ad,並創建一個實例賦給它 AsyncDelegate andl = new AsyncDelegate(ad.TestMethod);//聲明一個AsyncDelegate類型的對象andl,並讓他指向ad對象的TestMethod方法 IAsyncResult ar = andl.BeginInvoke(3000, out threadID, null, null);//執行andl的BeginInvoke方法,返回一個IAsyncResult類型的實例對象給ar變量,其實是一個號碼牌(不知道這樣說是否形象) Thread.Sleep(10);//使當前線程睡眠10毫秒(其實可去掉這句,我寫這個的目的是確保異步線程已啟動,再執行以下語句) Console.WriteLine("Main Thread {0} Does Some Work", AppDomain.GetCurrentThreadId());//輸出當前線程的id string ret = andl.EndInvoke(out threadID, ar);//使用EndInvoke方法,傳入out或ref類型參數和在調用BeginInvoke方法時得到的IAsyncResult,此時主線程將等待異步調用執行完畢,返回結果后執行以下語句 Console.WriteLine("The call executed on thread {0},with return value : {1}", threadID, ret); Console.ReadLine(); } } } ok,以上是第一種直接使用EndInvoke來等待異步調用完成的方法 ================================================ ================================================ 第二種方法是借助返回的IAsyncHandle的WaitHandle屬性的WaitOne()方法實現線程同步后,執行代碼,然后將要執行的代碼執行后隨時可調用EndInvoke方法。 示例代碼基本沒有什么改動,只是在BeginInvoke方法后執行一個ar.WaitHandle.WaitOne()方法,該方法將阻塞主線程使主線程等待返回ar的begininvoke調用的方法的線程執行完畢(不要怪我說話有點繞,我是說的詳細,否則你弄不明白,仔細看這句話就明白了^o^)。 本着一切代碼都是紙老虎的原則,請仔細分析下面的代碼 其實和示例1基本無異 ,只是使用WaitOne()方法同步了一下線程而已 using System; using System.Collections.Generic; using System.Text; using System.Threading; namespace sample { class AsyncDemo { public string TestMethod(int callDuration, out int threadid) { Console.WriteLine("Test Method begins"); Thread.Sleep(callDuration); threadid = AppDomain.GetCurrentThreadId(); return "MyCallTime was" + callDuration.ToString(); } } public delegate string AsyncDelegate(int callDuration, out int threadid); class Program { static void Main(string[] args) { int threadID; AsyncDemo ad = new AsyncDemo(); AsyncDelegate andl = new AsyncDelegate(ad.TestMethod); IAsyncResult ar = andl.BeginInvoke(3000, out threadID, null, null); Thread.Sleep(10); Console.WriteLine("Main Thread {0} Does Some Work", AppDomain.GetCurrentThreadId()); ar.AsyncWaitHandle.WaitOne();//執行該方法時主線程將等待輔助線程執行完畢,使兩線程同步后再執行以下語句 Console.WriteLine("其實很簡單");//執行一些方法 string ret = andl.EndInvoke(out threadID, ar);//使用EndInvoke來獲取返回結果和傳入ref和out的變量獲取修改后的實例的位置(這我就不太好用語言來表述了,你自己心領神會吧) Console.WriteLine("The call executed on thread {0},with return value : {1}", threadID, ret); Console.ReadLine(); } } }