c#中Invoke與BeginInvoke的用法及說(shuō)明
c# Invoke與BeginInvoke
最近在學(xué)習(xí)線程時(shí),發(fā)現(xiàn)當(dāng)我創(chuàng)建的線程需要訪問(wèn)UI界面的時(shí),會(huì)發(fā)生異常,原因是我在跨線程調(diào)用主線程的控件,因此windows GUI編程有一個(gè)規(guī)則,就是只能通過(guò)創(chuàng)建控件的線程來(lái)操作控件的數(shù)據(jù),否則就可能產(chǎn)生不可預(yù)料的結(jié)果。
有時(shí)候,我們不得不跨線程調(diào)用主界面的控件來(lái)進(jìn)行操作,所以為了方便的解決問(wèn)題,.net為我們提供了Invoke 與beginInvoke
Invoke 與begininvoke區(qū)別在于,invoke會(huì)阻塞當(dāng)前線程,直到invoke調(diào)用結(jié)束,才會(huì)繼續(xù)執(zhí)行下去,而begininvoke 則可以異步進(jìn)行調(diào)用,也就是該方法封送完畢后馬上返回,不會(huì)等待委托方法的執(zhí)行結(jié)束,調(diào)用者線程將不會(huì)被阻塞。但是調(diào)用者也可以使用EndInvoke方法或者其它類似WaitHandle機(jī)制等待異步操作的完成。
先講下Invoke
? ? ? ? // 定義委托函數(shù) ,委托函數(shù)與被委托函數(shù)必須要有相同返回值和參數(shù)列表
? ? ? ? public delegate void myDelegate(string str); ?
? ? ? ? public void _invoke_myDelegate(String str)
? ? ? ? {
? ? ? ? ? ? // invokeRequired 獲取一個(gè)bool值 判斷調(diào)用控件是否必須要調(diào)用invoke方法
? ? ? ? ? ? // 如果調(diào)用對(duì)象在其他線程,則返回true,否則返回false
? ? ? ? ? ? if (this.InvokeRequired)
? ? ? ? ? ? {
? ? ? ? ? ? ? ?/* Action<string> action = new Action<string>(_invoke_myDelegate);*/
? ? ? ? ? ? ? ?// 確定調(diào)用對(duì)象在其他線程 則調(diào)用invoke函數(shù) 它會(huì)返回到擁有這個(gè)控件的線程上
? ? ? ? ? ? ? ?// ?利用委托函數(shù),再次調(diào)用被委托函數(shù),str為委托函數(shù)的參數(shù)列表
? ? ? ? ? ? ? ?this.Invoke(new myDelegate(_invoke_myDelegate), str);
? ? ? ? ? ? }
? ? ? ? ? ? // 當(dāng)委托函數(shù)執(zhí)行時(shí), 此時(shí)已經(jīng)回到控件線程,可以直接調(diào)用控件label
? ? ? ? ? ? label1.Text = str;
? ? ? ? }這里Invoke 必須等委托函數(shù)調(diào)用完成之后,才會(huì)執(zhí)行后面操作,那么當(dāng)我們的委托函數(shù)執(zhí)行的是一個(gè)非常耗時(shí)的操作
這樣線程就會(huì)被阻塞,造成用戶界面卡頓的情況,所以,為了解決invoke同步的問(wèn)題,還有一種就是beginInvoke
BeginInvoke
BeginInvoke方法觸發(fā)你的異步方法,它和你想要執(zhí)行的異步方法有相同的參數(shù)。
另外還有兩個(gè)可選參數(shù)
- 1.第一個(gè)是AsyncCallback委托是異步完成的回調(diào)方法。
- 2.第二個(gè)是用戶自定義對(duì)象,該對(duì)象將傳遞到回調(diào)方法中。
BeginInvoke立即返回并且不等待完成異步的調(diào)用(繼續(xù)執(zhí)行該下面的代碼,不需要等待)。
BeginInvoke返回IAsyncResult接口,可用于檢測(cè)異步調(diào)用的過(guò)程。
通過(guò)EndInvoke方法檢測(cè)異步調(diào)用的結(jié)果。如果異步調(diào)用尚未完成,EndInvoke將阻塞調(diào)用線程,直到它完成。EndInvoke參數(shù)包括out和ref參數(shù)。
不管怎么么樣,調(diào)用了beginInvoke ,就必須調(diào)用endInvoke 結(jié)束異步,
那我們?cè)趺床拍苤朗裁磿r(shí)候異步結(jié)束呢?
常見(jiàn)四種方法:
- 1.做一些其他操作,然后調(diào)用EndInvoke方法阻塞線程直到該方法完成。
- 2.使用IAsyncResult.AsyncWaitHandle屬性,使用它的WaitOne方法阻塞線程直到收到WaitHandle信號(hào),然后調(diào)用EndInvoke。
- 3.檢查BeginInvoke返回值IAsyncResult的狀態(tài)來(lái)決定方法是否完成,然后調(diào)用EndInvoke方法。
- 4.通過(guò)在BeginInvoke方法中傳遞該委托,在回調(diào)方法中調(diào)用該委托的EndInvoke方法。
? ?AsyncMethodCaller caller = new AsyncMethodCaller(TestMethodAsync); // caller 為委托函數(shù)
? ? ? ? ? ? int threadid = 0;
? ? ? ? ? ? //開(kāi)啟異步操作
? ? ? ? ? ? IAsyncResult result = caller.BeginInvoke(1000, out threadid, null, null);
? ? ? ? ? ? for (int i = 0; i < 10; i++)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? Console.WriteLine("其它業(yè)務(wù)" + i.ToString());
? ? ? ? ? ? }
? ? ? ? ? ? //調(diào)用EndInvoke,等待異步執(zhí)行完成
? ? ? ? ? ? Console.WriteLine("等待異步方法TestMethodAsync執(zhí)行完成");
? ? ? ? ? ? //等待異步執(zhí)行完畢信號(hào)
? ? ? ? ? ? //result.AsyncWaitHandle.WaitOne();
? ? ? ? ? ? //Console.WriteLine("收到WaitHandle信號(hào)");
? ? ? ? ? ? //通過(guò)循環(huán)不停的檢查異步運(yùn)行狀態(tài)
? ? ? ? ? ? while (result.IsCompleted==false)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? Thread.Sleep(100);
? ? ? ? ? ? ? ? Console.WriteLine("異步方法,running........");
? ? ? ? ? ? }
? ? ? ? ? ? //異步結(jié)束,拿到運(yùn)行結(jié)果
? ? ? ? ? ? string res = caller.EndInvoke(out threadid, result);
? ? ? ? ? ? //顯示關(guān)閉句柄
? ? ? ? ? ? result.AsyncWaitHandle.Close();
? ? ? ? ? ? Console.WriteLine("關(guān)閉了WaitHandle句柄");
static string TestMethodAsync(int callDuration, out int threadId)
? ? ? ? {
? ? ? ? ? ? Stopwatch sw = new Stopwatch();
? ? ? ? ? ? sw.Start();
? ? ? ? ? ? Console.WriteLine("異步TestMethodAsync開(kāi)始");
? ? ? ? ? ? for (int i = 0; i < 5; i++)
? ? ? ? ? ? { ? // 模擬耗時(shí)操作
? ? ? ? ? ? ? ? Thread.Sleep(callDuration);
? ? ? ? ? ? ? ? Console.WriteLine("TestMethodAsync:" + i.ToString());
? ? ? ? ? ? }
? ? ? ? ? ? sw.Stop();
? ? ? ? ? ? threadId = Thread.CurrentThread.ManagedThreadId;
? ? ? ? ? ? return string.Format("耗時(shí){0}ms.", sw.ElapsedMilliseconds.ToString());
? ? ? ? }總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
C#實(shí)現(xiàn)自定義ListBox背景的示例詳解
這篇文章主要為大家詳細(xì)介紹了如何利用C#實(shí)現(xiàn)自定義ListBox背景,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C#有一定的幫助,感興趣的小伙伴可以跟隨小編一起了解一下2022-12-12
C#如何讀寫應(yīng)用程序配置文件App.exe.config,并在界面上顯示
這篇文章主要介紹了C#如何讀寫應(yīng)用程序配置文件App.exe.config,并在界面上顯示問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06
unity使用socket實(shí)現(xiàn)聊天室功能
這篇文章主要為大家詳細(xì)介紹了unity使用socket實(shí)現(xiàn)聊天室功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-03-03
DevExpress實(shí)現(xiàn)TreeList向上遞歸獲取符合條件的父節(jié)點(diǎn)
這篇文章主要介紹了DevExpress實(shí)現(xiàn)TreeList向上遞歸獲取符合條件的父節(jié)點(diǎn),需要的朋友可以參考下2014-08-08
C#語(yǔ)言中字符類char的使用方法(總結(jié))
下面小編就為大家?guī)?lái)一篇C#語(yǔ)言中字符類char的使用方法(總結(jié))。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-03-03

