




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
1、Visual C#中的多線程編程C#是.Net平臺的通用開發(fā)工具,它能夠建造所有的.Net應(yīng)用。在.Net中所有線程都運行在應(yīng)用程序域(AppDomain)中,這也許讓你想到Win32進程,實際上它們還是有很大的不同。應(yīng)用程序域提供了一種安全而通用的處理單元,公共語言運行庫可使用它來隔離應(yīng)用程序。注意在.Net中應(yīng)用程序的隔離是應(yīng)用程序域而不是進程,在單個進程中可以存在幾個應(yīng)用程序域,而且線程可以跨越應(yīng)用程序域的范圍,某個線程中的方法可以調(diào)用另一個線程的方法,這樣的話就不會造成進程間調(diào)用或進程間切換等方面的額外開銷。可以說應(yīng)用程序域是物理進程(也即win32中的Process)內(nèi)的邏輯進程。在
2、Visul C#中System.Threading 命名空間提供一些使得可以進行多線程編程的類和接口,其中線程的創(chuàng)建有以下三種方法:Thread、ThreadPool、Timer。下面我就它們的使用方法逐個作一簡單介紹。1 Thread這也許是最復(fù)雜的方法,但它提供了對線程的各種靈活控制。首先你必須使用它的構(gòu)造函數(shù)創(chuàng)建一個線程實例,它的參數(shù)比較簡單,只有一個ThreadStart 委托:C#public Thread(ThreadStart start);然后調(diào)用Start()啟動它,當(dāng)然你可以利用它的Priority屬性來設(shè)置或獲得它的運行優(yōu)先級(enum ThreadPriori
3、ty: Normal、 Lowest、 Highest、 BelowNormal、 AboveNormal)。見下例:它首先生成了兩個線程實例t1和t2,然后分別設(shè)置它們的優(yōu)先級,接著啟動兩線程(兩線程基本一樣,只不過它們輸出不一樣,t1為“1”,t2為“2”,根據(jù)它們各自輸出字符個數(shù)比可大致看出它們占用CPU時間之比,這也反映出了它們各自的優(yōu)先級)。 static void Main(string args) Thread t1 = new Thread(new ThreadStart(Thread1);
4、0; Thread t2 = new Thread(new ThreadStart(Thread2); t1.Priority = ThreadPriority.BelowNormal ; t2.Priority = ThreadPriority.Lowest ; t1.Start(); t2.Start(); public static void Thread1()
5、0; for (int i = 1; i < 1000; i+) /每運行一個循環(huán)就寫一個“1”dosth(); Console.Write("1"); public static void Thread2() for (int i = 0; i < 1000; i+) /
6、每運行一個循環(huán)就寫一個“2” dosth(); Console.Write("2"); public static void dosth() /用來模擬復(fù)雜運算 for (int j = 0; j < 10000000; j+)
7、160;int a=15; a = a*a*a*a; 以上程序運行結(jié)果為:推薦精選111111111111111111111111111111111111111111211111111111111111111111111111111111111111121111111111111111111111111111111111111111112111111111111111111111111111111111111111111211111111111111111111111111111111111
8、111111121111111111111111111111111111111111111111112 從以上結(jié)果我們可以看出,t1線程所占用CPU的時間遠比t2的多,這是因為t1的優(yōu)先級比t2的高,若我們把t1和t2的優(yōu)先級都設(shè)為Normal,那結(jié)果是如何?它們所占用的CPU時間會一樣嗎?是的,正如你所料,見下圖: 12121122121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212
9、1212推薦精選121212121212121212 從上例我們可看出,它的構(gòu)造類似于win32的工作線程,但更加簡單,只需把線程要調(diào)用的函數(shù)作為委托,然后把委托作為參數(shù)構(gòu)造線程實例即可。當(dāng)調(diào)用Start()啟動后,便會調(diào)用相應(yīng)的函數(shù),從那函數(shù)第一行開始執(zhí)行。 接下來我們結(jié)合線程的ThreadState屬性來了解線程的控制。ThreadState是一個枚舉類型,它反映的是線程所處的狀態(tài)。當(dāng)一個Thread實例剛創(chuàng)建時,它的ThreadState是Unstarted;當(dāng)此線程被調(diào)用Start()啟動之后,它的ThreadState是 Runn
10、ing; 在此線程啟動之后,如果想讓它暫停(阻塞),可以調(diào)用Thread.Sleep() 方法,它有兩個重載方法(Sleep(int )、Sleep(Timespan )),只不過是表示時間量的格式不同而已,當(dāng)在某線程內(nèi)調(diào)用此函數(shù)時,它表示此線程將阻塞一段時間(時間是由傳遞給 Sleep 的毫秒數(shù)或Timespan決定的,但若參數(shù)為0則表示掛起此線程以使其它線程能夠執(zhí)行,指定 Infinite 以無限期阻塞線程),此時它的ThreadState將變?yōu)閃aitSleepJoin,另外值得注意一點的是Sleep()函數(shù)被定義為了static?! 這也意味著它不能和某個線程實例結(jié)合起來用,也即不存在
11、類似于t1.Sleep(10)的調(diào)用!正是如此,Sleep()函數(shù)只能由需“Sleep”的線程自己調(diào)用,不允許其它線程調(diào)用,正如when to Sleep是個人私事不能由它人決定。但是當(dāng)某線程處于WaitSleepJoin狀態(tài)而又不得不喚醒它時,可使用Thread.Interrupt 方法 ,它將在線程上引發(fā)ThreadInterruptedException,下面我們先看一個例子(注意Sleep的調(diào)用方法):static void Main(string args) Thread t1 = new Thread(new Thread
12、Start(Thread1); t1.Start(); t1.Interrupt ();E.WaitOne ();t1.Interrupt (); t1.Join(); Console.WriteLine(“t1 is end”); static AutoResetEvent E = new AutoResetEvent(false); public static void Thread1()
13、60; try /從參數(shù)可看出將導(dǎo)致休眠 Thread.Sleep(Timeout.Infinite); catch(System.Threading.ThreadInterruptedException e) /中斷處理程序 Console.WriteLine (" 1st interrupt");
14、; E.Set (); try / 休眠 Thread.Sleep(Timeout.Infinite ); catch(System.Threading.ThreadInterruptedException e) Console.WriteLine (" 2nd interrupt"); /暫停10秒&
15、#160; Thread.Sleep (10000); 運行結(jié)果為: 1st interrupt 2nd interrupt (10s后)t1 is end 從上例我們可以看出Thread.Interrupt方法可以把程序從某個阻塞(WaitSleepJoin)狀態(tài)喚醒進入對應(yīng)的中斷處理程序,然后繼續(xù)往下執(zhí)行(它的ThreadState也變?yōu)镽unning),此函數(shù)的使用必須注意以下幾點:1 .此方法不僅可喚醒由Sleep導(dǎo)致的阻塞,而且對一切可導(dǎo)致線程進入WaitSleepJoin狀態(tài)的方法(如Wait和Join)都有效。
16、如上例所示, 使用時要把導(dǎo)致線程阻塞的方法放入try塊內(nèi), 并把相應(yīng)的中斷處理程序放入catch塊內(nèi)。2 .對某一線程調(diào)用Interrupt, 如它正處于WaitSleepJoin狀態(tài), 則進入相應(yīng)的中斷處理程序執(zhí)行, 若此時它不處于WaitSleepJoin狀態(tài), 則它后來進入此狀態(tài)時, 將被立即中斷。若在中斷前調(diào)用幾次Interrupt, 只有第一次調(diào)用有效, 這正是上例我用同步的原因, 這樣才能確保第二次調(diào)用Interrupt在第一個中斷后調(diào)用,否則的話可能導(dǎo)致第二次調(diào)用無效(若
17、它在第一個中斷前調(diào)用)。你可以把同步去掉試試,其結(jié)果很可能是: 1st interrupt上例還用了另外兩個使線程進入WaitSleepJoin狀態(tài)的方法:利用同步對象和Thread.Join方法。Join方法的使用比較簡單,它表示在調(diào)用此方法的當(dāng)前線程阻塞直至另一線程(此例中是t1)終止或者經(jīng)過了指定的時間為止(若它還帶了時間量參數(shù)),當(dāng)兩個條件(若有)任一出現(xiàn),它立即結(jié)束WaitSleepJoin狀態(tài)進入Running狀態(tài)(可根據(jù).Join方法的返回值判斷為何種條件,為true,則是線程終止;false則是時間到)。線程的暫停還可用Thread.Suspend方法,
18、當(dāng)某線程處于Running狀態(tài)時對它調(diào)用Suspend方法,它將進入SuspendRequested狀態(tài),但它并不會被立即掛起,直到線程到達安全點之后它才可以將該線程掛起,此時它將進入Suspended狀態(tài)。如對一個已處于Suspended的線程調(diào)用則無效,要恢復(fù)運行只需調(diào)用Thread.Resume即可。 最后我們談的是線程的銷毀,我們可以對需銷毀的線程調(diào)用Abort方法,它會在此線程上引發(fā)ThreadAbortException。我們可把線程內(nèi)的一些代碼放入try塊內(nèi),并把相應(yīng)處理代碼放入相應(yīng)的catch塊內(nèi),當(dāng)線程正執(zhí)行try塊內(nèi)代碼時如被調(diào)用Abort,它便會跳入相應(yīng)的ca
19、tch塊內(nèi)執(zhí)行,執(zhí)行完catch快內(nèi)的代碼后它將終止(若catch塊內(nèi)執(zhí)行了ResetAbort則不同了:它將取消當(dāng)前Abort請求,繼續(xù)向下執(zhí)行。所以如要確保某線程終止的最好用Join,如上例)。2 ThreadPool線程池(ThreadPool)是一種相對較簡單的方法,它適應(yīng)于一些需要多個線程而又較短任務(wù)(如一些常處于阻塞狀態(tài)的線程) ,它的缺點是對創(chuàng)建的線程不能加以控制,也不能設(shè)置其優(yōu)先級。由于每個進程只有一個線程池,當(dāng)然每個應(yīng)用程序域也只有一個線程池(對線),所以你將發(fā)現(xiàn)ThreadPool類的成員函數(shù)都為static! 當(dāng)你首次調(diào)用ThreadPool.QueueUser
20、WorkItem、ThreadPool.RegisterWaitForSingleObject等,便會創(chuàng)建線程池實例。下面我就線程池當(dāng)中的兩函數(shù)作一介紹:C#public static bool QueueUserWorkItem( 推薦精選/調(diào)用成功則返回trueWaitCallback callBack,/要創(chuàng)建的線程調(diào)用的委托 object state /傳遞給委托的參數(shù))/它的另一個重載函數(shù)類似,只是委托不帶參數(shù)而已 此函數(shù)的作用是把要創(chuàng)建的線程排隊到線程池,當(dāng)線程池的可用線程數(shù)不為零時(線程池有創(chuàng)建線程數(shù)的限制,缺身值為25),便創(chuàng)建此線程,否則就排隊到線程池等到它有可用
21、的線程時才創(chuàng)建。C#public static RegisteredWaitHandle RegisterWaitForSingleObject( WaitHandle waitObject,/ 要注冊的 WaitHandle WaitOrTimerCallback callBack,/ 線程調(diào)用的委托 object state,/傳遞給委托的參數(shù) int TimeOut,/超時,單位為毫秒, bool executeOnlyOnce file:/是否只執(zhí)行一次); publ
22、ic delegate void WaitOrTimerCallback( object state,/也即傳遞給委托的參數(shù) bool timedOut/true表示由于超時調(diào)用,反之則因為waitObject); 此函數(shù)的作用是創(chuàng)建一個等待線程,一旦調(diào)用此函數(shù)便創(chuàng)建此線程,在參數(shù)waitObject變?yōu)榻K止?fàn)顟B(tài)或所設(shè)定的時間TimeOut到了之前,它都處于“阻塞”狀態(tài),值得注意的一點是此“阻塞”與Thread的WaitSleepJoin狀態(tài)有很大的不同:當(dāng)某Thread處于WaitSleepJoin狀態(tài)時CPU會定期的喚醒它以輪詢更新狀態(tài)信息,
23、然后再次進入WaitSleepJoin狀態(tài),線程的切換可是很費資源的;而用此函數(shù)創(chuàng)建的線程則不同,在觸發(fā)它運行之前,CPU不會切換到此線程,它既不占用CPU的時間又不浪費線程切換時間,但CPU又如何知道何時運行它?實際上線程池會生成一些輔助線程用來監(jiān)視這些觸發(fā)條件,一旦達到條件便啟動相應(yīng)的線程,當(dāng)然這些輔助線程本身也占用時間,但是如果你需創(chuàng)建較多的等待線程時,使用線程池的優(yōu)勢就越加明顯。見下例:static AutoResetEvent ev=new AutoResetEvent(false); public static int Main(string args)
24、60; ThreadPool.RegisterWaitForSingleObject( ev, new WaitOrTimerCallback(WaitThreadFunc), 4, 2000, false/表示每次完成等待操作后都重置計時器,直到注銷等待 ); ThreadPool.QueueUserWorkItem (new WaitCallback (ThreadFunc),8); Thread.Sleep (10000); return 0;
25、0; public static void ThreadFunc(object b) Console.WriteLine ("the object is 0",b); for(int i=0;i<2;i+) Thread.Sleep (1000); ev.Set(); public static void WaitThreadFunc(object b,bool t)
26、; Console.WriteLine ("the object is 0,t is 1",b,t); 其運行結(jié)果為: the object is 8the object is 4,t is Falsethe object is 4,t is Falsethe object is 4,t is Truethe object is 4,t is Truethe object is 4,t is True從以上結(jié)果我們可以看出線程ThreadFunc運行了1次,而WaitThread
27、Func運行了5次。我們可以從WaitOrTimerCallback中的bool t參數(shù)判斷啟動此線程的原因:t為false,則表示由于waitObject,否則則是由于超時。另外我們也可以通過object b向線程傳遞一些參數(shù)。3 Timer 它適用于需周期性調(diào)用的方法,它不在創(chuàng)建計時器的線程中運行,它在由系統(tǒng)自動分配的單獨線程中運行。這和Win32中的SetTimer方法類似。它的構(gòu)造為:C#public Timer( TimerCallback callback,/所需調(diào)用的方法 object
28、state,/傳遞給callback的參數(shù) int dueTime,/多久后開始調(diào)用callback int period/調(diào)用此方法的時間間隔);/ 如果 dueTime 為0,則 callback 立即執(zhí)行它的首次調(diào)用。如果 dueTime 為 Infinite,則 callback 不調(diào)用它的方法。計時器被禁用,但使用 Change 方法可以重新啟用它。如果 period 為0或 Infinite,并且 dueTime 不為 Infinite,則 callback 調(diào)用它的方法一次。計時器的定期行為被禁用,但使用 Change 方法可以重新啟用它。如果 period 為零 (0) 或 Infinite,并且 dueTime 不為 Infinite,則 callback 調(diào)用它的方法一次。計時器的定期行為被禁用,但使用 Change 方法可以重新啟用它。在創(chuàng)建計時器之后若想改變它的period和dueTime,我們可以通過調(diào)用Timer的Change方法來改變:C#public bool Change( int dueTime,
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 浙江警官職業(yè)學(xué)院《醫(yī)學(xué)信息檢索與利用(4)》2023-2024學(xué)年第二學(xué)期期末試卷
- 甘肅林業(yè)職業(yè)技術(shù)學(xué)院《鐵路旅客運輸》2023-2024學(xué)年第二學(xué)期期末試卷
- 乘法-隊列表演(二)教學(xué)設(shè)計-2023-2024學(xué)年三年級下冊數(shù)學(xué)北師大版
- 一個時代歌者的赤子深情-名著導(dǎo)讀:《艾青詩選》如何讀詩(教學(xué)設(shè)計)九年級語文上冊同步高效課堂(統(tǒng)編版)
- 咸陽師范學(xué)院《專業(yè)新聞與深度報道》2023-2024學(xué)年第二學(xué)期期末試卷
- 遼寧何氏醫(yī)學(xué)院《建筑室內(nèi)聲學(xué)設(shè)計》2023-2024學(xué)年第二學(xué)期期末試卷
- 成都信息工程大學(xué)《高聚物合成工藝及設(shè)備》2023-2024學(xué)年第二學(xué)期期末試卷
- 泉州輕工職業(yè)學(xué)院《文化學(xué)導(dǎo)論》2023-2024學(xué)年第二學(xué)期期末試卷
- Unit 2 Were Family!Section B 2a-2b 教學(xué)設(shè)計2024-2025學(xué)年人教版(2024)七年級英語上冊
- 中山大學(xué)《黑白圖像》2023-2024學(xué)年第二學(xué)期期末試卷
- 北京市東城區(qū)2025年公開招考539名社區(qū)工作者高頻重點提升(共500題)附帶答案詳解
- 2025福建福州地鐵集團限公司運營分公司校園招聘高頻重點提升(共500題)附帶答案詳解
- 2025至2030年中國電子護眼臺燈數(shù)據(jù)監(jiān)測研究報告
- 2025年浙江省溫州樂清市融媒體中心招聘4人歷年高頻重點提升(共500題)附帶答案詳解
- 2025夏季廣東廣州期貨交易所招聘高頻重點提升(共500題)附帶答案詳解
- 2025上海市嘉定工業(yè)區(qū)農(nóng)村青年干部招聘22人歷年高頻重點提升(共500題)附帶答案詳解
- 《獸醫(yī)基礎(chǔ)》練習(xí)題及參考答案
- 2025年煤礦探放水證考試題庫
- 農(nóng)業(yè)機械設(shè)備運輸及調(diào)試方案
- 污水處理設(shè)備的故障處理指南考核試卷
- ps 課件教學(xué)課件
評論
0/150
提交評論