多線程編程的詳細(xì)說(shuō)明完整版_第1頁(yè)
多線程編程的詳細(xì)說(shuō)明完整版_第2頁(yè)
多線程編程的詳細(xì)說(shuō)明完整版_第3頁(yè)
多線程編程的詳細(xì)說(shuō)明完整版_第4頁(yè)
多線程編程的詳細(xì)說(shuō)明完整版_第5頁(yè)
已閱讀5頁(yè),還剩8頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、VB .NET多線程編程的詳細(xì)說(shuō)明作者:陶剛        更新時(shí)間:2011-4-1介紹傳統(tǒng)的Visual Basic開發(fā)人員已經(jīng)建立了同步應(yīng)用程序,在這些程序中事務(wù)按順序執(zhí)行。盡管由于多個(gè)事務(wù)多多少少地同時(shí)運(yùn)行使多線程應(yīng)用程序效率更高,但是使用先前版本的Visual Basic很難建立這類程序。 多線程程序是可行的,因?yàn)椴僮飨到y(tǒng)是多任務(wù)的,它有模擬同一時(shí)刻運(yùn)行多個(gè)應(yīng)用程序的能力。盡管多數(shù)個(gè)人計(jì)算機(jī)只有一個(gè)處理器,但是現(xiàn)在的操作系統(tǒng)還是通過(guò)在多個(gè)執(zhí)行代碼片斷之間劃分處理器時(shí)間提供了多任務(wù)。線程可能是整個(gè)應(yīng)用程序,但通常是應(yīng)

2、用程序可以單獨(dú)運(yùn)行的一個(gè)部分。操作系統(tǒng)根據(jù)線程的優(yōu)先級(jí)和離最近運(yùn)行的時(shí)間長(zhǎng)短給每一個(gè)線程分配處理時(shí)間。多線程對(duì)于時(shí)間密集型事務(wù)(例如文件輸入輸出)應(yīng)用程序的性能有很大的提高。 但是也有必須細(xì)心的地方。盡管多線程能提高性能,但是每個(gè)線程還是需要用附加的內(nèi)存來(lái)建立和處理器時(shí)間來(lái)運(yùn)行,建立太多的線程可能降低應(yīng)用程序的性能。當(dāng)設(shè)計(jì)多線程應(yīng)用程序時(shí),應(yīng)該比較性能與開銷。 多任務(wù)成為操作系統(tǒng)的一部分已經(jīng)很久了。但是直到最近Visual Basic程序員才能使用無(wú)文檔記錄特性(undocumented)或者間接使用COM組件或者操作系統(tǒng)的異步部分執(zhí)行多線程事務(wù)。.NET框架組件為開發(fā)多線程應(yīng)用程序,在Sys

3、tem.Threading名字空間中提供了全面的支持。 本文討論多線程的好處以及怎樣使用Visual Basic .NET開發(fā)多線程應(yīng)用程序。盡管Visual Basic .NET和.NET框架組件使開發(fā)多線程應(yīng)用程序更容易,但是本文作了調(diào)整使其適合高級(jí)讀者和希望從早期Visual Basic轉(zhuǎn)移到Visual Basic .NET的開發(fā)人員。 多線程處理的優(yōu)點(diǎn)盡管同步應(yīng)用程序易于開發(fā),但是它們的性能通常比多線程應(yīng)用程序低,因?yàn)橐粋€(gè)新的事務(wù)必須等待前面的事務(wù)完成后才能開始。如果完成某個(gè)同步事務(wù)的時(shí)間比預(yù)想的要長(zhǎng),應(yīng)用程序可能沒(méi)有響應(yīng)。多線程處理可以同時(shí)運(yùn)行多個(gè)過(guò)程。例如,字處理程序能夠在繼續(xù)操

4、作文檔的同時(shí)執(zhí)行拼寫檢查事務(wù)。因?yàn)槎嗑€程應(yīng)用程序把程序分解為獨(dú)立的事務(wù),它們能通過(guò)下面的途徑充分提高性能: l 多線程技術(shù)可以使程序更容易響應(yīng),因?yàn)樵谄渌ぷ骼^續(xù)時(shí)用戶界面可以保持激活。 l 當(dāng)前不忙的事務(wù)可以把處理器時(shí)間讓給其它事務(wù)。 l 花費(fèi)大量處理時(shí)間的事務(wù)可以周期性的把時(shí)間讓給其它的事務(wù)。 l 事務(wù)可以在任何時(shí)候停止。 l 可以通過(guò)把單獨(dú)事務(wù)的優(yōu)先級(jí)調(diào)高或調(diào)低來(lái)優(yōu)化性能。 明確地建立多線程應(yīng)用程序的決定依賴于幾個(gè)因素。多線程最適合下面的情況: l 時(shí)間密集或處理密集的事務(wù)妨礙用戶界面。 l 單獨(dú)的事務(wù)必須等待外部資源,例如遠(yuǎn)程文件或Internet連接。 例如,某個(gè)應(yīng)用程序跟隨Web頁(yè)

5、面上的鏈接并下載符合特定條件的文件。這種應(yīng)用程序可以同步一個(gè)接一個(gè)地下載文件或者使用多線程在同一時(shí)刻下載多個(gè)文件。多線程的方法比同步方法的效率高得多,因?yàn)榧词鼓承┚€程從遠(yuǎn)程Web服務(wù)器上接收到的響應(yīng)很慢,文件也可以被下載。  建立新線程建立線程的最直接的方法是建立線程類的一個(gè)新的實(shí)例并且使用AddressOf語(yǔ)句替你希望運(yùn)行的過(guò)程傳遞一個(gè)委托。例如下面的代碼運(yùn)行一個(gè)作為單獨(dú)的線程的叫做SomeTask的子過(guò)程。 Dim Thread1 As New System.Threading.Thread(AddressOf SomeTask) Thread1.Start ' 這兒的代

6、碼立即運(yùn)行這就是建立和啟動(dòng)線程的全部工作。調(diào)用線程的Start方法后面的任何代碼立即執(zhí)行,不需要等待前面線程的結(jié)束。 下表是你能使用的控制單獨(dú)線程的方法: 上面的大多數(shù)方法字面上容易理解,但是安全點(diǎn)(safe point)的概念對(duì)你來(lái)說(shuō)可能是新的。安全點(diǎn)是代碼中的某個(gè)位置,在這個(gè)位置通用語(yǔ)言運(yùn)行時(shí)可以安全地執(zhí)行自動(dòng)無(wú)用單元收集(garbage collection,釋放無(wú)用變量并恢復(fù)內(nèi)存的過(guò)程)。當(dāng)調(diào)用線程的Abort或Suspend方法時(shí),通用語(yǔ)言運(yùn)行時(shí)分析代碼,決定線程停止運(yùn)行的適當(dāng)位置。 下表是線程的一些常用的屬性: 當(dāng)建立和管理線程時(shí)它的屬性和方法很重要。本文的"線程同步&q

7、uot;部分將討論你怎樣使用這些屬性和方法控制和調(diào)整線程。 線程參數(shù)和返回值前面例子中的線程調(diào)用沒(méi)有參數(shù)和返回值。這是使用這種方法建立和運(yùn)行線程的主要缺點(diǎn)之一。但是,你可以在類或結(jié)構(gòu)體中包裝線程,為運(yùn)行在單獨(dú)線程上的過(guò)程提供和返回參數(shù)。 Class TasksClassFriend StrArg As String Friend RetVal As Boolean Sub SomeTask() ' StrArg字段是一個(gè)參數(shù) MsgBox("The StrArg contains the string " & StrArg) RetVal = True &#

8、39; 設(shè)置返回參數(shù)中的返回值 End Sub End Class ' 為了使用這個(gè)類,設(shè)置存儲(chǔ)參數(shù)的屬性或者字段,接著異步調(diào)用需要的方法 Sub DoWork() Dim Tasks As New TasksClass() Dim Thread1 As New System.Threading.Thread(AddressOf Tasks.SomeTask) Tasks.StrArg = "Some Arg" ' 設(shè)置作為參數(shù)使用的字段 Thread1.Start() ' 啟動(dòng)新線程 Thread1.Join() ' 等待線程1結(jié)束 

9、9; 顯示返回值 MsgBox("Thread 1 returned the value " & Tasks.RetVal) End Sub手工建立和管理線程最適合于希望很好地控制細(xì)節(jié)(例如線程的優(yōu)先級(jí)和線程模型)的應(yīng)用程序。你可能想象,通過(guò)這種方法管理大量的線程是很困難的。在你需要很多線程時(shí)考慮使用線程池來(lái)減小復(fù)雜程度。 線程池線程池是多線程的一種形式,在它里面,事務(wù)被添加到一個(gè)隊(duì)列,并隨著線程的建立自動(dòng)啟動(dòng)。有了線程池,你使用希望運(yùn)行的過(guò)程的委托調(diào)用Threadpool.QueueUserWorkItem方法,Visual Basic .NET就建立線程并運(yùn)行該

10、過(guò)程。下面的例子演示了怎樣使用線程池啟動(dòng)幾個(gè)事務(wù): Sub DoWork() ' 對(duì)一個(gè)事務(wù)排隊(duì) TPool.QueueUserWorkItem(New System.Threading.WaitCallback(AddressOf SomeLongTask) ' 對(duì)另一個(gè)事務(wù)排隊(duì) TPool.QueueUserWorkItem(New System.Threading.WaitCallback(AddressOf AnotherLongTask)End Sub當(dāng)你需要啟動(dòng)很多單獨(dú)事務(wù)而不需要單獨(dú)設(shè)置每個(gè)線程的屬性時(shí),線程池是很有用的。每個(gè)線程使用默認(rèn)的棧大小和優(yōu)先級(jí)啟動(dòng)。默認(rèn)

11、情況下,每個(gè)系統(tǒng)處理器可以運(yùn)行高達(dá)25個(gè)線程池線程。超過(guò)限制的線程可以排隊(duì),但是直到其它線程結(jié)束才能啟動(dòng)。 線程池的一個(gè)優(yōu)點(diǎn)是你能把狀態(tài)對(duì)象中的參數(shù)傳遞給每個(gè)事務(wù)過(guò)程。如果調(diào)用的過(guò)程需要一個(gè)以上參數(shù),你可以把一個(gè)結(jié)構(gòu)體或類的示例轉(zhuǎn)換為Object數(shù)據(jù)類型。 參數(shù)和返回值從線程池線程返回值有點(diǎn)棘手。從函數(shù)調(diào)用返回值的標(biāo)準(zhǔn)方法在這兒是不允許的,因?yàn)镾ub過(guò)程是能被線程池排隊(duì)的唯一過(guò)程類型。提供參數(shù)和返回值的途徑是把這些參數(shù),返回值和方法包裝進(jìn)一個(gè)包裝類。提供參數(shù)和返回值的一個(gè)更簡(jiǎn)單的方法是使用QueueUserWorkItem方法的ByVal狀態(tài)對(duì)象變量。如果使用該變量傳遞引用給類的一個(gè)實(shí)例,實(shí)例

12、中的成員能被線程池線程修改并作為返回值使用。起先可以修改值傳遞的變量所引用的對(duì)象是不明顯的,由于只有對(duì)象引用被值傳遞了,它才是可能的。當(dāng)你修改對(duì)象引用引用的對(duì)象的成員時(shí),改變應(yīng)用到實(shí)際類的實(shí)例。 結(jié)構(gòu)體不能用于在狀態(tài)對(duì)象內(nèi)部返回值。因?yàn)榻Y(jié)構(gòu)體是值類型的,異步處理做的改變不會(huì)改變?cè)Y(jié)構(gòu)體的成員。當(dāng)不需要返回值時(shí)使用結(jié)構(gòu)體提供參數(shù)。 Friend Class StateObj Friend StrArg As String Friend IntArg As Integer Friend RetVal As StringEnd ClassSub ThreadPoolTest() Dim StObj1

13、 As New StateObj() Dim StObj2 As New StateObj() ' 設(shè)置狀態(tài)對(duì)象中的作為參數(shù)的一些字段 StObj1.IntArg = 10 StObj1.StrArg = "Some string" StObj2.IntArg = 100 StObj2.StrArg = "Some other string" ' 對(duì)一個(gè)事務(wù)進(jìn)行排隊(duì) TPool.QueueUserWorkItem(New System.Threading.WaitCallback _ (AddressOf SomeOtherTask),

14、StObj1) ' 對(duì)另一個(gè)事務(wù)進(jìn)行排隊(duì) TPool.QueueUserWorkItem(New System.Threading.WaitCallback _ (AddressOf AnotherTask), StObj2)End SubSub SomeOtherTask(ByVal StateObj As Object) ' 使用狀態(tài)對(duì)象字段作為參數(shù) Dim StObj As StateObj StObj = CType(StateObj, StateObj) ' 轉(zhuǎn)換成正確的類型 MsgBox("StrArg contains the string &q

15、uot; & StObj.StrArg) MsgBox("IntArg contains the number " & CStr(StObj.IntArg) ' 使用一個(gè)字段作為返回值 StObj.RetVal = "Return Value from SomeOtherTask"End SubSub AnotherTask(ByVal StateObj As Object) ' 使用狀態(tài)對(duì)象作為參數(shù)。狀態(tài)對(duì)象作為Object傳遞。把它轉(zhuǎn)換為特定類型使使用更容易 Dim StObj As StateObj StObj =

16、CType(StateObj, StateObj) MsgBox("StrArg contains the String " & StObj.StrArg) MsgBox("IntArg contains the number " & CStr(StObj.IntArg) ' 使用一個(gè)字段作為返回值 StObj.RetVal = "Return Value from AnotherTask"End Sub通用語(yǔ)言運(yùn)行時(shí)自動(dòng)為排隊(duì)的線程池事務(wù)建立線程,當(dāng)這些事務(wù)完成時(shí)釋放這些資源。一旦事務(wù)被排隊(duì)了,這就不是取消事

17、務(wù)的容易的方法了。ThreadPool線程使用多線程單元(MTA)線程模型運(yùn)行。如果你希望線程使用單線程單元模型(STA)運(yùn)行,必須手工建立線程。 線程同步同步提供了多線程編程的無(wú)組織特性和同步處理的有組織次序之間一種折衷的方法。使用同步技術(shù)能夠達(dá)到的目標(biāo): l 在事務(wù)必須按特定次序執(zhí)行的時(shí)候,明確地控制代碼運(yùn)行的次序。 l 當(dāng)兩個(gè)線程在同一時(shí)刻共享相同的資源的時(shí)候防止錯(cuò)誤的發(fā)生。 例如,你可以使用同步來(lái)引發(fā)一個(gè)顯示過(guò)程等待另一個(gè)線程上運(yùn)行的數(shù)據(jù)檢索過(guò)程結(jié)束。 有兩種同步的途徑,輪詢(polling)和使用同步對(duì)象。輪詢是從某個(gè)循環(huán)中周期性地檢查異步調(diào)用的狀態(tài)。輪詢是管理線程的效率最低的方法,

18、因?yàn)樗芷谛詸z查多樣線程屬性的狀態(tài),浪費(fèi)了資源。 例如當(dāng)輪詢查看某個(gè)線程是否終止時(shí)會(huì)使用IsAlive屬性。使用這個(gè)屬性必須注意,因?yàn)橛行У木€程不是一定運(yùn)行的。你可以使用ThreadState屬性獲得線程狀態(tài)的更多詳細(xì)信息。因?yàn)樵诮o定的時(shí)刻線程可能有一個(gè)以上的狀態(tài),ThreadState中存儲(chǔ)的值可能是System.Threading.Threadstate枚舉中值的組合。因此輪詢時(shí)你必須仔細(xì)檢查所有的相關(guān)線程狀態(tài)。例如,如果線程的狀態(tài)顯示它不是Running的,它有可能結(jié)束了。另一方面,它也可能掛起或休眠了。 你可以想象,輪詢?yōu)榱藫Q取對(duì)線程次序的控制犧牲了多線程的一些優(yōu)點(diǎn)。效率更高的途徑是使

19、用Join方法控制線程。Join引發(fā)調(diào)用過(guò)程等待一個(gè)線程完成或者超時(shí)(如果指定了超時(shí)值)。Join這個(gè)名字基于建立新線程,它是執(zhí)行路徑中的分叉。你使用Join方法把單獨(dú)的執(zhí)行路徑合并成單個(gè)線程。 圖1.線程 有一點(diǎn)必須清楚,Join是同步的或阻塞的調(diào)用。一旦你調(diào)用Join或等待句柄的等待方法,調(diào)用過(guò)程會(huì)停止并等待線程發(fā)出完成信號(hào)。 Sub JoinThreads() Dim Thread1 As New System.Threading.Thread(AddressOf SomeTask) Thread1.Start() Thread1.Join() ' 等待該線程結(jié)束 MsgBox(

20、"Thread is done")End Sub這些簡(jiǎn)單的控制線程的方法對(duì)管理少量的線程是有用的,但是在大型項(xiàng)目中使用困難。下一部分討論用于同步的一些高級(jí)技術(shù)。 高級(jí)同步技術(shù)多線程應(yīng)用程序通常使用等待處理和監(jiān)視對(duì)象來(lái)同步多個(gè)線程。下表是.NET框架組件中能用于同步線程的一些類: 等待句柄等待句柄是把某個(gè)線程的狀態(tài)信號(hào)發(fā)送給另一個(gè)線程的對(duì)象。當(dāng)線程需要獨(dú)占訪問(wèn)某種資源時(shí),它們可以使用等待句柄通知其它線程。其它線程必須等待這些資源,直到等待句柄不再使用。等待句柄有兩種狀態(tài):signaled和nonsignaled。不屬于任何線程的等待句柄狀態(tài)為signaled。屬于某個(gè)線程的等

21、待句柄的狀態(tài)是nonsignaled。 線程通過(guò)調(diào)用一個(gè)等待方法(例如WaitOne、 WaitAny或 WaitAll)來(lái)請(qǐng)求等待句柄的所有權(quán)。等待方法也是阻塞調(diào)用,與獨(dú)立線程的Join方法類似。 l 如果其它線程沒(méi)有擁有等待句柄,該調(diào)用立即返回True,等待線程的狀態(tài)變?yōu)閚onsignaled,擁有等待句柄的線程繼續(xù)運(yùn)行。 l 如果某個(gè)線程調(diào)用等待句柄的一個(gè)等待方法,但是等待句柄屬于另一個(gè)線程,發(fā)出調(diào)用的線程要么等待一個(gè)特定時(shí)間(如果指定了超時(shí)值)或者等待不確定的時(shí)長(zhǎng)(沒(méi)有指定超時(shí)值)直到其它線程釋放等待句柄。如果設(shè)置了超時(shí)值并且等待句柄在期滿前被釋放了,該調(diào)用將返回True。否則,該調(diào)用

22、返回False,發(fā)送調(diào)用的線程繼續(xù)運(yùn)行。 當(dāng)擁有等待句柄的線程完成后或者它們?cè)僖膊恍枰却浔鷷r(shí),它們調(diào)用Set方法。其它線程可以通過(guò)調(diào)用Reset方法或WaitOne、WaitAll、 WaitAny把等待句柄的狀態(tài)復(fù)位成nonsignaled,并且成功地等待某個(gè)線程調(diào)用Set。當(dāng)某個(gè)等待線程被釋放后系統(tǒng)自動(dòng)把AutoResetEvent句柄復(fù)位成nonsignaled。如果沒(méi)有線程在等待,該事件對(duì)象的狀態(tài)仍然為signaled。 Visual Basic .NET中通常使用三類等待句柄:互斥對(duì)象、ManualResetEvent和AutoResetEvent。后兩種通常用于同步事件。 互斥

23、對(duì)象互斥對(duì)象都是同步對(duì)象,它們只能在一個(gè)時(shí)刻由一個(gè)線程擁有。實(shí)際上,互斥這個(gè)名字衍生自互斥對(duì)象的所有權(quán)是相互排斥的。當(dāng)線程請(qǐng)求獨(dú)占訪問(wèn)某種資源時(shí),它們請(qǐng)求互斥對(duì)象的所有權(quán)。因?yàn)樵谀硞€(gè)時(shí)刻只有一個(gè)線程能擁有一個(gè)互斥對(duì)象,其它線程在使用資源前必須等待互斥對(duì)象的所有權(quán)。 WaitOne方法引發(fā)一個(gè)調(diào)用線程等待互斥對(duì)象的所有權(quán)。如果擁有互斥對(duì)象的線程正常終止,該互斥對(duì)象的狀態(tài)就被設(shè)置為signaled,下一個(gè)線程獲得它的所有權(quán)。 同步事件同步事件用于通知其它的線程發(fā)生了某種事情或者某種資源可用。不要被它使用了"事件"這個(gè)詞迷惑了。同步事件與其它的Visual Basic事件不同,它

24、是真正的等待句柄。與其它的等待句柄類似,同步事件有兩種狀態(tài)signaled 和nonsignaled。調(diào)用同步事件的某個(gè)等待方法的線程必須等待,直到其它線程調(diào)用Set方法給事件發(fā)信號(hào)。有兩個(gè)同步事件類。線程使用Set方法把ManualResetEvent實(shí)例的狀態(tài)設(shè)置為signaled。線程使用Reset方法或控制返回等待WaitOne調(diào)用把實(shí)例的狀態(tài)設(shè)置為nonsignaled。AutoResetEvent類的實(shí)例也可以使用Set設(shè)置為signaled,但是只要通知等待線程事件變?yōu)閟ignaled,它們自動(dòng)返回到nonsignaled。 下面的例子使用AutoResetEvent類同步線程池

25、事務(wù)。 Sub StartTest() Dim AT As New AsyncTest() AT.StartTask()End SubClass AsyncTest Private Shared AsyncOpDone As New System.Threading.AutoResetEvent(False) Sub StartTask() Dim arg As String = "SomeArg" Tpool.QueueUserWorkItem(New System.Threading.WaitCallback( _ AddressOf Task), arg) '

26、 對(duì)一個(gè)事務(wù)進(jìn)行排隊(duì) AsyncOpDone.WaitOne() ' 等待該線程調(diào)用Set MsgBox("Thread is done.") End Sub Sub Task(ByVal Arg As Object) MsgBox("Thread is starting.") System.Threading.Thread.Sleep(4000) ' 等待4秒. MsgBox("The state object contains the string " & CStr(Arg) AsyncOpDone.Set

27、() ' 發(fā)信號(hào)表明該線程完成了 End SubEnd Class監(jiān)視對(duì)象和同步鎖監(jiān)視對(duì)象確保代碼塊的運(yùn)行不被運(yùn)行在其它線程中的代碼打斷。換句話說(shuō),其它線程中的代碼不能運(yùn)行,直到被同步的代碼塊結(jié)束。在Visual Basic .NET中使用SyncLock關(guān)鍵字來(lái)簡(jiǎn)化監(jiān)視對(duì)象的訪問(wèn)。在Visual C# .NET中使用Lock關(guān)鍵字。 例如,假定你有一個(gè)程序,它重復(fù)地、異步讀取數(shù)據(jù)并顯示結(jié)果。使用優(yōu)先多任務(wù)操作系統(tǒng),正在運(yùn)行的線程可以因?yàn)椴僮飨到y(tǒng)允許其它的線程運(yùn)行而被打斷。如果沒(méi)有同步,數(shù)據(jù)正在顯示時(shí),顯示數(shù)據(jù)的對(duì)象被其它的線程修改,有可能得到的是部分更新的數(shù)據(jù)視圖。SyncLock保

28、證一段代碼持續(xù)運(yùn)行,不被打斷。下面的例子顯示了怎樣使用SyncLock給顯示過(guò)程提供數(shù)據(jù)對(duì)象的獨(dú)占訪問(wèn)。 Class DataObject Public ObjText As String Public ObjTimeStamp As DateEnd ClassSub RunTasks() Dim MyDataObject As New DataObject() ReadDataAsync(MyDataObject) SyncLock MyDataObject DisplayResults(MyDataObject) End SyncLockEnd SubSub ReadDataAsync(B

29、yRef MyDataObject As DataObject) ' 添加異步讀取和處理數(shù)據(jù)的代碼End SubSub DisplayResults(ByVal MyDataObject As DataObject) ' 添加顯示結(jié)果的代碼End Sub當(dāng)有一段代碼不能被某個(gè)獨(dú)立的線程中運(yùn)行的代碼打斷時(shí)使用SyncLock。 Interlocked類你可以使用Interlocked類的方法防止多個(gè)線程同時(shí)更新或比較同一個(gè)值的問(wèn)題發(fā)生。這個(gè)類的方法讓你安全地增加、減少、交換和比較來(lái)自任何線程的值。下面的例子演示了怎樣使用Increment方法增加一個(gè)運(yùn)行在獨(dú)立線程上的多個(gè)過(guò)程共享

30、的變量的值。 Sub ThreadA(ByRef IntA As Integer) System.Threading.Interlocked.Increment(IntA)End SubSub ThreadB(ByRef IntA As Integer) System.Threading.Interlocked.Increment(IntA)End SubReaderWriter鎖在有些情況下,你可能希望只在寫數(shù)據(jù)時(shí)鎖定資源,在數(shù)據(jù)沒(méi)有更新完前允許多個(gè)客戶同時(shí)讀數(shù)據(jù)。某個(gè)線程正在修改資源時(shí),ReaderWriterLock類加強(qiáng)了對(duì)該資源的獨(dú)占訪問(wèn),但是允許讀取資源的非獨(dú)占訪問(wèn)。ReaderW

31、riter鎖是排他鎖的一個(gè)有用的備選方案,排他鎖引起其它線程等待,即使這些線程不需要更新數(shù)據(jù)。下面的例子演示了怎樣使用ReaderWriter調(diào)整來(lái)自多個(gè)線程的讀和寫操作。 Class ReadWrite ' ReadData和WriteData方法可以被多個(gè)線程安全地調(diào)用 Public ReadWriteLock As New System.Threading.ReaderWriterLock()Sub ReadData()' 這個(gè)過(guò)程從數(shù)據(jù)源讀取信息。在允許其它線程調(diào)用ReadData時(shí),讀取鎖放置任何數(shù)據(jù)寫入直到讀取完成 ReadWriteLock.AcquireRead

32、erLock(System.Threading.Timeout.Infinite) Try ' 此處執(zhí)行數(shù)據(jù)操作FinallyReadWriteLock.ReleaseReaderLock() ' 釋放讀取鎖End Try End Sub Sub WriteData() ' 這個(gè)過(guò)程向數(shù)據(jù)源寫信息。寫入鎖防止數(shù)據(jù)被讀取或者寫入知道線程完成寫操作。 ReadWriteLock.AcquireWriterLock(System.Threading.Timeout.Infinite) Try ' 此處執(zhí)行寫操作 Finally ReadWriteLock.Releas

33、eWriterLock() ' 釋放寫入鎖 End Try End SubEnd Class死鎖在多線程應(yīng)用程序中線程同步是無(wú)價(jià)之寶,但是始終有多個(gè)線程彼此等待的死鎖的危險(xiǎn)。類似汽車停在四條路上,彼此等待對(duì)方前進(jìn),死鎖使所有動(dòng)作停止。不用說(shuō),避免死鎖很重要。有很多種途徑會(huì)造成死鎖,同樣有多種方法可以避免它們。盡管本文沒(méi)有足夠的篇幅討論死鎖相關(guān)的問(wèn)題,但是重要的一點(diǎn)是細(xì)心計(jì)劃是避免死鎖的關(guān)鍵。你可以在開始編碼前用圖解法表示應(yīng)用程序,預(yù)計(jì)死鎖的情形。 線程計(jì)時(shí)器Threading.Timer類對(duì)于在獨(dú)立的線程上周期性地運(yùn)行事務(wù)是很有用的。例如,你可以使用線程計(jì)時(shí)器檢查數(shù)據(jù)庫(kù)的狀態(tài)和完整性或

34、者備份關(guān)鍵文件。下面的例子每?jī)擅雴?dòng)一個(gè)事務(wù),并使用一個(gè)標(biāo)記來(lái)初始化停止計(jì)時(shí)器的Dispose方法。這個(gè)例子把狀態(tài)發(fā)送到輸出窗口,因此在測(cè)試代碼前你可以通過(guò)按Control+Alt+O使窗口可見(jiàn)。 Class StateObjClass ' 為TimerTask調(diào)用保持參數(shù) Public SomeValue As Integer Public TimerCanceled As BooleanEnd ClassSub RunTimer() Dim StateObj As New StateObjClass() StateObj.TimerCanceled = False StateObj

35、.SomeValue = 1 Dim TimerDelegate As New Threading.TimerCallback(AddressOf TimerTask) ' 建立一個(gè)定時(shí)器每2秒調(diào)用一個(gè)過(guò)程。注意:這兒沒(méi)有Start方法,計(jì)時(shí)器在實(shí)例被建立時(shí)啟動(dòng)它 Dim TimerItem As New System.Threading.Timer(TimerDelegate, StateObj, 2000, 2000) StateObj.TimerReference = TimerItem ' 為Dispose保存一個(gè)引用 While StateObj.SomeValue

36、< 10 ' 執(zhí)行10次 System.Threading.Thread.Sleep(1000) ' 等待1秒 End While StateObj.TimerCanceled = True ' 請(qǐng)求計(jì)時(shí)器對(duì)象的DisposeEnd SubSub TimerTask(ByVal StateObj As Object)DimState As StateObjClass = CType(StateObj, StateObjClass) Dim x As Integer ' 使用interlocked類增加計(jì)數(shù)器變量的值 System.Threading.Int

37、erlocked.Increment(State.SomeValue) Debug.WriteLine("Launched new thread " & Now) If State.TimerCanceled Then ' 請(qǐng)求Dispose State.TimerReference.Dispose() Debug.WriteLine("Done " & Now) End IfEnd Sub取消事務(wù)多線程的優(yōu)點(diǎn)之一是應(yīng)用程序的用戶界面保持響應(yīng)時(shí),事務(wù)可以在其它的線程上運(yùn)行。同步事件和作為標(biāo)記的字段通常用于通知其它線程你希望停止它。

38、下面的例子使用同步事件取消一個(gè)事務(wù)。為了使用這個(gè)例子,給項(xiàng)目添加下面的模塊。調(diào)用StartCancel.StartTask()啟動(dòng)一個(gè)線程,調(diào)用StartCancel.CancelTask()取消一個(gè)或多個(gè)正在運(yùn)行的線程。 Module StartCancel Public CancelThread As New System.Threading.ManualResetEvent(False) Public ThreadisCanceled As New System.Threading.ManualResetEvent(False) Private Sub SomeLongTask() Dim LoopCount As Integ

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論