1,、定義 線程是操作系統(tǒng)分配CPU時間片的基本單位,每個運行的引用程序為一個進程,,這個進程可以包含一個或多個線程,。 線程是進程中的執(zhí)行流程,每個線程可以得到一小段程序的執(zhí)行時間,,在單核處理器中,,由于切換線程速度很快因此感覺像是線程同時允許,其實任意時刻都只有一個線程運行,,但是在多核處理器中,,可以實現(xiàn)混合時間片和真實的并發(fā)執(zhí)行。但是由于操作系統(tǒng)自己的服務或者其他應用程序執(zhí)行,,也不能保證一個進程中的多個線程同時運行,。 線程被一個CLR委托給操作系統(tǒng)的進程協(xié)調(diào)函數(shù)管理,確保所有線程都可以被分配適當?shù)膱?zhí)行時間,,同時保證在等待或阻止的線程不占用執(zhí)行時間,。 2、理解 線程與進程的關鍵區(qū)別是:進程是彼此隔離的,,進程是操作系統(tǒng)分配資源的基本單位,,而同一個進程中的多個線程是共享該進程內(nèi)存堆區(qū)(Heap)的數(shù)據(jù)的,可以進行直接的數(shù)據(jù)共享,。但是對于同一進程內(nèi)的不同線程維護各自的內(nèi)存棧(Stack),,因此各線程的局部變量是隔離的。通過下面的例子可以看出,。
二,、線程使用情形
問題: 多線程的問題是使程序中的多個線程的交互變得過于復雜,會帶來較長的開發(fā)時間和間歇性或非重復性的bug,。同時線程數(shù)目不能太多,,否則頻繁的分配和切換線程會帶來資源和CPU的開銷,一般有一個到兩個工作線程就足夠,。 三,、C#中的線程C#中主要使用Thread類進行線程操作,位于System.Threading命名空間下,,提供了一系列進行多線程編程的類和接口,,有線程同步和數(shù)據(jù)訪問的Mutex、Monitor,、Interlocked和AutoResetEvent類,,以及ThreadPool類和Timer類等。 首先使用new Thread()創(chuàng)建出新的線程,然后調(diào)用Start方法使得線程進入就緒狀態(tài),,得到系統(tǒng)資源后就執(zhí)行,,在執(zhí)行過程中可能有等待、休眠,、死亡和阻塞四種狀態(tài),。正常執(zhí)行結(jié)束時間片后返回到就緒狀態(tài)。如果調(diào)用Suspend方法會進入等待狀態(tài),,調(diào)用Sleep或者遇到進程同步使用的鎖機制而休眠等待,。具體過程如下圖所示: Thread類主要用來創(chuàng)建并控制線程,設置線程的狀態(tài),、優(yōu)先級等,。創(chuàng)建線程的時候使用ThreadStart委托或者ParameterizedThreadStart委托來執(zhí)行線程所關聯(lián)的部分代碼(也就是工作線程的運行代碼)。
四、創(chuàng)建與運行設置1,、創(chuàng)建
使用Thread類的構造函數(shù)創(chuàng)建線程的時候,,需要傳遞一個新線程開始執(zhí)行的代碼塊,提供了使用無參數(shù)的TheadStart委托和帶有一個參數(shù)的ParameterizedTheadStart委托,。他們的定義如下:
任何時候C#使用上述兩個委托中的一個自動進行線程的創(chuàng)建,。
上述方式不傳遞參數(shù),可以使用new Thead(Go)的方式直接創(chuàng)建,,此時C#會在編譯時自動匹配使用的是ThreadStart委托創(chuàng)建的,。下面可以進行傳遞參數(shù)創(chuàng)建線程。
此時實際在編譯時使用的new Thread(new ParameterizedThreadStart(Go("hello")))創(chuàng)建的,,上述使用Start方法傳遞的參數(shù)會默認采用這種方式構建,。 第二種方法是使用Lambda表達式:
第三種方法是使用匿名方法:
注意問題:使用Lambda表達式的時候會存在變量捕獲的問題,如果捕獲的變量是共享的,,會出現(xiàn)線程不安全的問題,。看下面的例子:
上述由于使用Lambda表達式傳遞參數(shù),,在for循環(huán)的作用域內(nèi),,新建的十個線程共享了局部變量i,傳遞進入i參數(shù)可能被多個線程已經(jīng)修改,,因此每次輸出結(jié)果都是不確定的,,兩次結(jié)果如下:
上述使用Lambda表達式傳遞參數(shù)的問題,,使用Start方法傳遞參數(shù)也會出現(xiàn)這樣的線程不安全的問題,需要使用特殊的線程同步手段進行避免,。
2,、設置 通過使用Thread.CurrentThread屬性獲取正在運行的線程對象。每個線程都有一個Name屬性,,可以設置和修改,,但是只能設置一次,。這樣可在調(diào)試窗口看到每個線程的工作狀態(tài),,便于調(diào)試。 線程有前臺和后臺之分,,可以使用IsBackground屬性設置,,但是這個屬性與線程的優(yōu)先級是沒有關聯(lián)的。前臺線程只要有一個在運行應用程序就在運行,,當沒有前臺線程運行后應用程序終止,,也就是在任務管理器中的程序一欄中沒有了此程序,但是此時后臺線程任然運行直到其完成操作結(jié)束,,因此在任務管理器的進程一欄中會找到,。
線程的優(yōu)先級使用Priority設置或獲取,只有在運行時才有作用,。分為5個級別:
線程優(yōu)先級設置高并不意味著能執(zhí)行實時的工作,,這受限于所屬進程的級別,要執(zhí)行實時的工作需要提示System.Diagnostics命名空間下的Process級別:
設置為High是一個短暫的最高優(yōu)先級別,,如果設置為Realtime,,那么將讓操作系統(tǒng)不然該進程被其他進程搶占,因此如果此程序一旦出現(xiàn)故障將耗盡操作系統(tǒng)資源,。因此設置為High就是被認為最高和最有用的進程級別了,。
對于有用戶界面的程序不適合提升進程級別,因為界面UI的更新需要耗費CPU很多時間,,從而拖慢電腦,。最好的方式是實時工作和用戶界面使用不同的進程,有不同的進程優(yōu)先級,,通過Remoting或者共享內(nèi)存的方式進行進程通信,。 線程執(zhí)行先運行最高優(yōu)先級的線程,,高優(yōu)先級的線程執(zhí)行完之后才開始執(zhí)行低優(yōu)先級的線程。 3,、休眠 Thread.Sleep(int ms); Thread.Sleep(TimeSpan timeout); 上述方法為Thread類的兩個靜態(tài)方法,,用來阻止當前線程指定的時間。 4,、終止 使用Abort和Join兩個方法實現(xiàn),。Join會等待另一個線程執(zhí)行完后再執(zhí)行。而Abort會引發(fā)ThreadAbortException異常,,同時可以傳遞一個終止的參數(shù)信息,。 Thread.Abort();或者Thread.Abort(Object stateInfo)。 5,、異常處理 每個線程都有獨立的執(zhí)行路徑,,因此放在try/catch/finally塊中的新線程都與之無關。補救的方式是在每個線程處理的方法中加入自己的異常處理機制,。
上述處理過程在單獨的線程運行中進行異常處理是可以被捕獲到的,。同時任何線程內(nèi)的未處理的異常都會導致整個程序關閉,對于WPF和WinForm程序中的全局異常僅僅在主界面線程執(zhí)行,,對于工作線程的異常需要手動處理,。有三種情況可以不用處理工作線程的異常:異步委托、BackgroundWroker,、Task Parallel Library,。
|
|
來自: 昵稱10504424 > 《工作》