版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
1、注:本文中出現(xiàn)的代碼均在 framework rc3 環(huán)境中運行通過多線程的概念. 錯誤 !未定義書簽。操縱一個線程. 錯誤 !未定義書簽。線程的同步和通訊生產(chǎn)者和消費者. 錯誤 !未定義書簽。線程池和定時器多線程的自動管理. 錯誤 !未定義書簽?;コ鈱ο蟾屿`活的同步方式. 錯誤 !未定義書簽。小結(jié) . 錯誤 !未定義書簽。多線程的概念windows是一個多任務(wù)的系統(tǒng),如果你使用的是windows 2000 及其以上版本,你可以通過任務(wù)管理器查看當(dāng)前系統(tǒng)運行的程序和進程。什么是進程呢當(dāng)一個程序開始運行時,它就是一個進程,進程所指包括運行中的程序和程序所使用到的內(nèi)存和系統(tǒng)資源。而一個進程又是由
2、多個線程所組成的,線程是程序中的一個執(zhí)行流,每個線程都有自己的專有寄存器( 棧指針、程序計數(shù)器等) ,但代碼區(qū)是共享的,即不同的線程可以執(zhí)行同樣的函數(shù)。多線程是指程序中包含多個執(zhí)行流,即在一個程序中可以同時運行多個不同的線程來執(zhí)行不同的任務(wù),也就是說允許單個程序創(chuàng)建多個并行執(zhí)行的線程來完成各自的任務(wù)。瀏覽器就是一個很好的多線程的例子, 在瀏覽器中你可以在下載java小應(yīng)用程序或圖象的同時滾動頁面, 在訪問新頁面時, 播放動畫和聲音, 打印文件等。多線程的好處在于可以提高cpu 的利用率任何一個程序員都不希望自己的程序很多時候沒事可干,在多線程程序中,一個線程必須等待的時候,cpu 可以運行其它
3、的線程而不是等待,這樣就大大提高了程序的效率。然而我們也必須認識到線程本身可能影響系統(tǒng)性能的不利方面,以正確使用線程:線程也是程序,所以線程需要占用內(nèi)存,線程越多占用內(nèi)存也越多多線程需要協(xié)調(diào)和管理,所以需要cpu時間跟蹤線程線程之間對共享資源的訪問會相互影響,必須解決競用共享資源的問題線程太多會導(dǎo)致控制太復(fù)雜,最終可能造成很多bug基于以上認識,我們可以一個比喻來加深理解。假設(shè)有一個公司,公司里有很多各司其職的職員,那么我們可以認為這個正常運作的公司就是一個進程,而公司里的職員就是線程。一個公司至少得有一個職員吧,同理,一個進程至少包含一個線程。在公司里,你可以一個職員干所有的事,但是效率很顯
4、然是高不起來的,一個人的公司也不可能做大;一個程序中也可以只用一個線程去做事,事實上,一些過時的語言如 fortune,basic都是如此,但是象一個人的公司一樣,效率很低,如果做大程序,效率更低事實上現(xiàn)在幾乎沒有單線程的商業(yè)軟件。公司的職員越多,老板就得發(fā)越多的薪水給他們,還得耗費大量精力去管理他們,協(xié)調(diào)他們之間的矛盾和利益;程序也是如此,線程越多耗費的資源也越多,需要cpu 時間去跟蹤線程,還得解決諸如死鎖,同步等問題??傊?,如果你不想你的公司被稱為“皮包公司”,你就得多幾個員工;如果你不想讓你的程序顯得稚氣,就在你的程序里引入多線程吧!本文將對 c#編程中的多線程機制進行探討,通過一些實
5、例解決對線程的控制,多線程間通訊等問題。為了省去創(chuàng)建gui那些繁瑣的步驟,更清晰地逼近線程的本質(zhì),下面所有的程序都是控制臺程序,程序最后的 () 是為了使程序中途停下來,以便看清楚執(zhí)行過程中的輸出。好了,廢話少說,讓我們來體驗一下多線程的c#吧!操縱一個線程任何程序在執(zhí)行時,至少有一個主線程,下面這段小程序可以給讀者一個直觀的印象:; ; public class simple public static int main() (thread start/stop/join sample); alpha oalpha = new alpha(); ,使之執(zhí)行alpha 類的 beta() 方法
6、thread othread = new thread(new threadstart); (); while (!; (1); (); (); (); ( has finished); try (try to restart the thread); (); catch (threadstateexception) (threadstateexception trying to restart . ); (expected since aborted threads cannot be restarted.); (); return 0; 這段程序包含兩個類alpha 和simple ,在創(chuàng)
7、建線程othread 時我們用指向() 方法的初始化了threadstart 代理( delegate )對象,當(dāng)我們創(chuàng)建的線程othread 調(diào)用 () 方法啟動時,實際上程序運行的是() 方法:alpha oalpha = new alpha(); thread othread = new thread(new threadstart); (); 然后在 main() 函數(shù)的 while 循環(huán)中, 我們使用靜態(tài)方法() 讓主線程停了1ms ,這段時間cpu轉(zhuǎn)向執(zhí)行線程 othread 。然后我們試圖用() 方法終止線程othread ,注意后面的 () ,() 方法使主線程等待,直到oth
8、read 線程結(jié)束。你可以給() 方法指定一個int型的參數(shù)作為等待的最長時間。之后,我們試圖用() 方法重新啟動線程othread ,但是顯然abort()方法帶來的后果是不可恢復(fù)的終止線程,所以最后程序會拋出threadstateexception異常。程序最后得到的結(jié)果將如下圖:在這里我們要注意的是其它線程都是依附于main() 函數(shù)所在的線程的,main() 函數(shù)是 c#程序的入口,起始線程可以稱之為主線程,如果所有的前臺線程都停止了,那么主線程可以終止,而所有的后臺線程都將無條件終止。而所有的線程雖然在微觀上是串行執(zhí)行的,但是在宏觀上你完全可以認為它們在并行執(zhí)行。讀者一定注意到了這個
9、屬性,這個屬性代表了線程運行時狀態(tài),在不同的情況下有不同的值,于是我們有時候可以通過對該值的判斷來設(shè)計程序流程。threadstate在各種情況下的可能取值如下:aborted :線程已停止abortrequested :線程的 () 方法已被調(diào)用,但是線程還未停止background :線程在后臺執(zhí)行,與屬性有關(guān)running :線程正在正常運行stopped :線程已經(jīng)被停止stoprequested :線程正在被要求停止suspended:線程已經(jīng)被掛起(此狀態(tài)下,可以通過調(diào)用resume()方法重新運行)suspendrequested :線程正在要求被掛起,但是未來得及響應(yīng)unsta
10、rted :未調(diào)用 () 開始線程的運行waitsleepjoin:線程因為調(diào)用了wait(),sleep()或 join()等方法處于封鎖狀態(tài)上面提到了 background狀態(tài)表示該線程在后臺運行,那么后臺運行的線程有什么特別的地方呢其實后臺線程跟前臺線程只有一個區(qū)別,那就是后臺線程不妨礙程序的終止。一旦一個進程所有的前臺線程都終止后, clr (通用語言運行環(huán)境)將通過調(diào)用任意一個存活中的后臺進程的abort()方法來徹底終止進程。當(dāng)線程之間爭奪cpu 時間時, cpu 按照是線程的優(yōu)先級給予服務(wù)的。在c# 應(yīng)用程序中,用戶可以設(shè)定5個不同的優(yōu)先級,由高到低分別是highest ,abo
11、venormal,normal,belownormal , lowest,在創(chuàng)建線程時如果不指定優(yōu)先級,那么系統(tǒng)默認為。給一個線程指定優(yōu)先級,我們可以使用如下代碼:ame=(); for (int i = 0; i 10; i+) threadsi.start(); (); 而多線程公用一個對象時,也會出現(xiàn)和公用代碼類似的問題,這種問題就不應(yīng)該使用lock 關(guān)鍵字了,這里需要用到中的一個類monitor ,我們可以稱之為監(jiān)視器,monitor提供了使線程共享資源的方案。monitor類可以鎖定一個對象,一個線程只有得到這把鎖才可以對該對象進行操作。對象鎖機制保證了在可能引起混亂的情況下一個時刻
12、只有一個線程可以訪問這個對象。monitor必須和一個具體的對象相關(guān)聯(lián),但是由于它是一個靜態(tài)的類,所以不能使用它來定義對象,而且它的所有方法都是靜態(tài)的,不能使用對象來引用。下面代碼說明了使用monitor鎖定一個對象的情形:. queue oqueue=new queue(); . (oqueue); . . produce: 20 consume: 20 事實上,這個簡單的例子已經(jīng)幫助我們解決了多線程應(yīng)用程序中可能出現(xiàn)的大問題,只要領(lǐng)悟了解決線程間沖突的基本方法,很容易把它應(yīng)用到比較復(fù)雜的程序中去。線程池和定時器多線程的自動管理在多線程的程序中,經(jīng)常會出現(xiàn)兩種情況。一種情況下,應(yīng)用程序中的線
13、程把大部分的時間花費在等待狀態(tài),等待某個事件發(fā)生,然后才能給予響應(yīng);而另外一種情況則是線程平常都處于休眠狀態(tài),只是周期性地被喚醒。在 framework里邊,我們使用threadpool 來對付第一種情況,使用timer 來對付第二種情況。threadpool 類提供一個由系統(tǒng)維護的線程池可以看作一個線程的容器,該容器需要windows 2000以上版本的系統(tǒng)支持,因為其中某些方法調(diào)用了只有高版本的windows才有的 api函數(shù)。你可以使用() 方法將線程安放在線程池里,該方法的原型如下:ookie); (=0, , , lock (hashcount) ,則添加之if (! 0); has
14、hcount = (int)hashcount int ix = 2000; (ix); ; w2k = false; if (w2k) for (int iitem=1;iitem maxcount;iitem+) . . queue to thread pool 9 waiting for thread pool to drain 98 0 : =0, 100 1 : =1, 98 2 : . . setting eventx thread pool has been drained (event fired) load across threads 101 2 100 3 98 4 10
15、2 1與threadpool 類不同, timer 類的作用是設(shè)置一個定時器,定時執(zhí)行用戶指定的函數(shù),而這個函數(shù)的傳遞是靠另外一個代理對象timercallback,它必須在創(chuàng)建timer 對象時就指定,并且不能更改。定時器啟動后,系統(tǒng)將自動建立一個新的線程,并且在這個線程里執(zhí)行用戶指定的函數(shù)。下面的語句初始化了一個timer 對象:timer timer = new timer(timerdelegate, s,1000, 1000); 第一個參數(shù)指定了timercallback代理對象;第二個參數(shù)的意義跟上面提到的waitcallback代理對象的一樣,作為一個傳遞數(shù)據(jù)的對象傳遞給要調(diào)用的
16、方法;第三個參數(shù)是延遲時間計時開始的時刻距現(xiàn)在的時間,單位是毫秒;第四個參數(shù)是定時器的時間間隔計時開始以后,每隔這么長的一段時間,timercallback所代表的方法將被調(diào)用一次,單位也是毫秒。這句話的意思就是將定時器的延遲時間和時間間隔都設(shè)為1 秒鐘。定時器的設(shè)置是可以改變的,只要調(diào)用 () 方法, 這是一個參數(shù)類型重載的方法,一般使用的原型如下: public bool change(long, long);下面這段代碼將前邊設(shè)置的定時器修改了一下: (10000,2000); 很顯然,定時器timer 的時間間隔被重新設(shè)置為2秒,停止計時 10秒后生效。下面這段程序演示了timer 類
17、的用法。using system; using ; class timerexamplestate public int counter = 0; public timer tmr; class app public static void main() timerexamplestate s = new timerexamplestate(); ; (); static void checkstatus(object state) timerexamplestate s =(timerexamplestate)state; +; (0 checking status 1., ; if = 5
18、) .change(10000,2000); (changed.); if = 10) (disposing of timer.); = null; 程序首先創(chuàng)建了一個定時器,它將在創(chuàng)建1秒之后開始每隔1秒調(diào)用一次 checkstatus()方法,當(dāng)調(diào)用 5次以后,在 checkstatus()方法中修改了時間間隔為2秒,并且指定在10秒后重新開始。當(dāng)計數(shù)達到10次,調(diào)用 () 方法刪除了timer對象,主線程于是跳出循環(huán),終止程序。程序執(zhí)行的結(jié)果如下:上面就是對 threadpool 和 timer 兩個類的簡單介紹,充分利用系統(tǒng)提供的功能,可以為我們省去很多時間和精力特別是對很容易出錯的多
19、線程程序。同時我們也可以看到framework 強大的內(nèi)置對象,這些將對我們的編程帶來莫大的方便。互斥對象更加靈活的同步方式有時候你會覺得上面介紹的方法好像不夠用,對,我們解決了代碼和資源的同步問題,解決了多線程自動化管理和定時觸發(fā)的問題,但是如何控制多個線程相互之間的聯(lián)系呢例如我要到餐廳吃飯,在吃飯之前我先得等待廚師把飯菜做好,之后我開始吃飯,吃完我還得付款,付款方式可以是現(xiàn)金,也可以是信用卡,付款之后我才能離開。分析一下這個過程,我吃飯可以看作是主線程,廚師做飯又是一個線程,服務(wù)員用信用卡收款和收現(xiàn)金可以看作另外兩個線程,大家可以很清楚地看到其中的關(guān)系我吃飯必須等待廚師做飯,然后等待兩個收
20、款線程之中任意一個的完成,然后我吃飯這個線程可以執(zhí)行離開這個步驟,于是我吃飯才算結(jié)束了。事實上,現(xiàn)實中有著比這更復(fù)雜的聯(lián)系,我們怎樣才能很好地控制它們而不產(chǎn)生沖突和重復(fù)呢?這種情況下,我們需要用到互斥對象,即命名空間中的mutex 類。大家一定坐過出租車吧,事實上我們可以把mutex 看作一個出租車,那么乘客就是線程了,乘客首先得等車,然后上車,最后下車,當(dāng)一個乘客在車上時,其他乘客就只有等他下車以后才可以上車。而線程與mutex 對象的關(guān)系也正是如此,線程使用 () 方法等待mutex 對象被釋放,如果它等待的mutex 對象被釋放了,它就自動擁有這個對象,直到它調(diào)用 () 方法釋放這個對象
21、,而在此期間,其他想要獲取這個mutex 對象的線程都只有等待。下面這個例子使用了mutex對象來同步四個線程,主線程等待四個線程的結(jié)束,而這四個線程的運行又是與兩個 mutex對象相關(guān)聯(lián)的。其中還用到autoresetevent 類的對象,如同上面提到的manualresetevent 對象一樣,大家可以把它簡單地理解為一個信號燈,使用() 方法可以設(shè)置它為有信號狀態(tài),而使用() 方法把它設(shè)置為無信號狀態(tài)。這里用它的有信號狀態(tài)來表示一個線程的結(jié)束。.); gm2 = new mutex(true); ( - main owns gm1 and gm2); autoresetevent evs
22、 = new autoresetevent4; evs0 = event1; ,t2,t3,t4定義 autoresetevent對象evs1 = event2; evs2 = event3; evs3 = event4; mutexsample tm = new mutexsample( ); thread t1 = new thread(new threadstart); thread t2 = new thread(new threadstart); thread t3 = new thread(new threadstart); thread t4 = new thread(new threadstart); ( );. mutex sample); (); public void t1start( ) (t1start started, (mutex); mutex gms = new mutex2; gms0 = gm1;/創(chuàng)建一個mutex 數(shù)組作為 () 方法的參數(shù)gms1 = gm2; (gms);/等待 gm1和 gm2都被釋放(2000); (t1start finished, (mutex) satisfied); ( ); ,將 event1 設(shè)置為有信號狀態(tài) public void t2sta
溫馨提示
- 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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 幼兒園園長個人工作計劃
- 中學(xué)生自我評價15篇
- 愛崗敬業(yè)演講稿范文集錦6篇
- 大一新生自我鑒定15篇
- 學(xué)期班務(wù)工作計劃
- 初中生新學(xué)期開學(xué)典禮演講稿合集6篇
- 大學(xué)課前三分鐘演講稿(合集15篇)
- 《廣告經(jīng)典案例》課件
- 幼兒園大班老師的綜合教育筆記合集6篇
- 金錢的詩句李白
- 北師大版九年級數(shù)學(xué)下冊《圓的對稱性》評課稿
- 《遙感原理與應(yīng)用》期末考試試卷附答案
- 工程分包管理制度
- GB/T 9452-2023熱處理爐有效加熱區(qū)測定方法
- 肺炎支原體肺炎診治專家共識
- 藥物化學(xué)(第七版)(全套課件1364P)
- 中國近現(xiàn)代史人物陳獨秀
- 建筑師《建筑工程經(jīng)濟》習(xí)題(E)
- 全過程工程造價跟蹤審計服務(wù)方案
- YS/T 937-2013鎳鉑靶材
- GB/T 700-1988碳素結(jié)構(gòu)鋼
評論
0/150
提交評論