.NET 框架与多线程 (转载)
生活随笔
收集整理的這篇文章主要介紹了
.NET 框架与多线程 (转载)
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
專欄作品 .NET 框架與多線程
袁劍
.NET 框架與多線程 本文發(fā)表在《程序春秋》2003年12期 摘要 本文介紹了.NET框架的基本概念并簡要的描述了如何利用.NET框架編寫多線程程序。 目錄 ? 概述 ? 功能特性 ? 編程模型 ? 線程概述 ? 線程控制 ? 線程同步 概述 Microsoft.NET代表了一個集合、一個環(huán)境、一個可以作為平臺支持下一代Internet的可編程結(jié)構(gòu),它通過使用HTTP,XML等標(biāo)準(zhǔn),使得各個系統(tǒng)平臺間互操作性成為現(xiàn)實,Microsoft.NET最重要部分是.NET框架,.NET框架是一種新的計算平臺,它簡化了在高度分布式Internet環(huán)境中的應(yīng)用程序開發(fā),它支持超過20種不同的編程語言,它幫助開發(fā)人員把精力集中在實現(xiàn)商業(yè)邏輯的核心上,使開發(fā)人員的經(jīng)驗在面對類型大不相同的應(yīng)用程序(如基于 Windows 的應(yīng)用程序和基于 Web 的應(yīng)用程序)時保持一致,在未來的版本中甚至僅僅在程序發(fā)布時才需要指定發(fā)布的類型(作為Win Form還是Web Form)。 如上圖,.NET框架由2部分組成:公共語言運行時(CLR:是.NET開發(fā)人員的源代碼和硬件底層之間的 中間媒介,所有的.NET 代碼都在CLR中運行)和框架類庫(FCL:包括數(shù)據(jù)訪問組件、基礎(chǔ)類庫以及WebForm、WinForm、Web Services模板)。 功能特性 CLR和FCL緊密結(jié)合在一起,提供了不同系統(tǒng)之間交叉與綜合的解決方案與服務(wù),創(chuàng)造了可控的、安全的、功能豐富的應(yīng)用開發(fā)環(huán)境,以下是它們提供的部分功能。 一次運行,總能運行 所有的開發(fā)人員幾乎都知道“Dll Hell”版本控制問題(當(dāng)新安裝的應(yīng)用程序的組件覆蓋舊有應(yīng)用程序的組件時,導(dǎo)致舊有程序無法正常運行)。為了徹底消除“DLL Hell”現(xiàn)象,.NET框架的結(jié)構(gòu)已與應(yīng)用程序組件隔離,應(yīng)用程序運行時必須加載生成時所用到的組件以確保應(yīng)用程序總是能正常運行。 簡化部署 在.NET框架里軟件安裝的方式是XCOPY,如同在DOS下一樣,只需要將應(yīng)用程序復(fù)制到某個目錄就完成了安裝,卸載應(yīng)用程序只需要刪除目錄。 自動內(nèi)存管理 對于托管資源您再也不必在類里寫析構(gòu)函數(shù)(Finalize)進(jìn)行清理,垃圾管理(GC)可以自動跟蹤資源使用,確保不會產(chǎn)生資源泄漏,實際上GC對Finalize的調(diào)用時間和次序是不確定的。但是微軟建議用戶一定要記得在Dispose 方法里釋放非托管資源如數(shù)據(jù)庫連接、文件等。 類型安全 每個對象都是單根繼承自O(shè)bject(注:也有人認(rèn)為是繼承自Iobject接口)以確保在運行時可以通過調(diào)用GetType方法可以確定對象的類型,通常強制轉(zhuǎn)換為基類型被認(rèn)為是安全的隱式轉(zhuǎn)換。CLR可以驗證所有代碼是否類型安全,類型安全能確??偸且约嫒莸姆绞皆L問被分配對象。 編程模型 以前在Windows平臺下進(jìn)行軟件開發(fā)的C++開發(fā)人員大多使用的是微軟基礎(chǔ)類庫(MFC)或者Win32 APIs,Visual Basic用戶使用的是Visual Basic API,Delphi用戶使用的是Borland公司的VCL,Java用戶使用JDK,彼此之間很難兼容、相互調(diào)用,軟件開發(fā)人員有時也難以取舍,而.NET框架統(tǒng)一了當(dāng)前各種不同的架構(gòu),.NET框架為開發(fā)人員提供了一個統(tǒng)一的、面向?qū)ο蟮?、層次化的、可擴展的框架類庫――FCL,開發(fā)人員不再需要學(xué)習(xí)多種架構(gòu)只須學(xué)習(xí).NET框架就能靈活的采用各種不同的編程語言進(jìn)行開發(fā),.NET框架還實現(xiàn)了跨語言的繼承、錯誤處理、調(diào)試。 在.NET框架里從C#,VB.NET,J#到C++的所有編程語言都是相互平等的,開發(fā)人員可以自由選擇自己喜歡的語言,如下不同語言的程序代碼: C#: class Hello { static void Main()//程序的出口點 { System.Console.Write( "Hello, World!" );//輸出Hello, World! } } VB.NET: Module Hello Sub Main() '程序的出口點 System.Console.Write( "Hello, World!" ) '輸出Hello, World! End Sub End Module 在編譯器上最終生成的都是如下的IL(中間語言)代碼: IL_0000: ldstr "Hello, World!" IL_0005: call void [mscorlib]System.Console::Write(string) IL_000a: ret IL是CLR唯一理解的編程語言,所有的編譯器都將源代碼編譯成IL,IL再被CLR處理。 輸出的結(jié)果是非常熟悉的:Hello, World!。 在.NET框架下您不僅可以開發(fā)傳統(tǒng)的基于Windows平臺下的應(yīng)用,您還可以開發(fā)基于Smart Phone、Pocket PC、Tablet PC等等平臺下的應(yīng)用。 .NET框架提供了強有力的編程模板,可以隨心所欲的編寫WinForm、WebForm、WebService等類型的程序,這些類型的程序的開發(fā)方式與以往有很大的不同,功能也比以往大大加強。其中“最有可能改變世界”的(注:Jeff Prosise語),最令人驚奇的應(yīng)該是Web Form(ASP.NET)。多線程、GDI+、設(shè)計模式、Cache、異常等等這些在以前的Web程序里不敢想象或者很難實現(xiàn)的功能在.NET框架下變得如此的垂手可得。 ASP.NET幾乎天生就是基于MVC模式的,它利用Code-Behind技術(shù)輕而易舉的把頁面(View)和代碼(Model && Control)分離,再加上Page Controller,Distributed,Services等模式,可以把程序結(jié)構(gòu)從傳統(tǒng)的3層擴充到4層、5層甚至更多層,充分滿足開發(fā)大型企業(yè)級應(yīng)用的需要(以后有機會將向大家展示ASP.NET結(jié)合模式開發(fā)令人激動的一面)。利用多線程和GDI+技術(shù)可以一邊顯示文字內(nèi)容、一邊從遠(yuǎn)程抓取圖片并把圖片變換為適當(dāng)?shù)男问?#xff08;如轉(zhuǎn)換為PNG格式,在圖片上記錄版權(quán)信息)顯示給用戶,效率比以往大大提高。 對于相當(dāng)多的人來說,開發(fā)多線程程序是一個相當(dāng)大的挑戰(zhàn),但.NET框架已對其進(jìn)行了相當(dāng)程度的簡化,本文的后面部分將向您介紹多線程編程的基礎(chǔ)知識,并提供一些用于試驗的示例代碼。相信您在看了之后會迅速掌握。 為了便于講解,示例代碼采用的是控制臺程序。 線程概述 線程是CPU時間片分配的單位,不同的線程可以具有不同的優(yōu)先級,每個進(jìn)程至少會有一個主線程。在.NET框架中最基本的執(zhí)行單元是線程,托管代碼是以單線程開始執(zhí)行的,但在執(zhí)行期間可以產(chǎn)生附加的線程來幫助完成指定的任務(wù)。線程分為前臺線程(所有前臺線程都必須退出之后,當(dāng)前進(jìn)程才能退出)和后臺線程(進(jìn)程隨時可以退出,不等待后臺線程退出)。 對于耗時非常長而又不想堵塞界面的操作、服務(wù)器端的應(yīng)用、同時支持多用戶并發(fā)的環(huán)境或者發(fā)揮多處理器的作用的時候都應(yīng)該考慮使用多線程,但是使用線程需要非常謹(jǐn)慎地分析同步情況和線程調(diào)度本身的開銷。 線程控制 線程控制包括線程啟動、掛起、恢復(fù)、休眠、終止等,在下面的這個列子里將會對線程控制做一個大體描述。 public class MyThread { public static void Work() { try { for( int i = 0; i < 4; i++ ) { Console.WriteLine( Thread.CurrentThread.Name + "正在計算" + i.ToString() ); Thread.Sleep( 50 ); } } catch( ThreadAbortException e ) { Console.WriteLine( "錯誤信息:{0}", e.Message ); Thread.ResetAbort();//取消主線程要求中止的請求,如不執(zhí)行則ThreadAbortException會在catch塊末端再次引發(fā) } Console.WriteLine( Thread.CurrentThread.Name + "完成工作!" ); } } class ThreadAbortTest { public static void Main() { Console.WriteLine( "主線程啟動!"); Thread thread = new Thread( new ThreadStart( MyThread.Work ) );//MyThread.Work代表要執(zhí)行的線程函數(shù),它可以是靜態(tài)的,也可以是某個類實例的方法,它是要執(zhí)行的線程函數(shù)的委托 thread.Name = "MyThread"; thread.Start();//線程啟動后將被CPU調(diào)度,但不一定是馬上執(zhí)行,所以同樣的例子在不同的機器上可能會有不同的結(jié)果。 Console.WriteLine( "主線程第一次休眠!"); Thread.Sleep( 100 ); Console.WriteLine( "MyThread被掛起!"); thread.Suspend();//掛起子線程 Console.WriteLine( "主線程第二次休眠!"); Thread.Sleep( 100 ); Console.WriteLine( "MyThread被恢復(fù)!"); thread.Resume();//恢復(fù)子線程 thread.Abort();//終止子線程 thread.Join();//直到到子線程完全終止了,主線程才繼續(xù)運行 Console.WriteLine( "主線程終止!" ); Console.ReadLine(); } } 程序啟動后會創(chuàng)建一個名為MyThread的輔助線程并通過調(diào)用thread.Start啟動它,然后調(diào)用Thread.Sleep( 100 )休眠100微妙,這時輔助線程一直在運行,接下來主線程調(diào)用thread.Suspend掛起輔助線程并再休眠100微妙后再調(diào)用Thread.Sleep恢復(fù)輔助線程,在被掛起和被恢復(fù)這段時間內(nèi)輔助線程被阻塞,緊跟著主線程執(zhí)行thread.Abort方法終止輔助線程并執(zhí)行thread.Join等待輔助線程結(jié)束,在輔助線程接收到終止請求時它已經(jīng)工作并又執(zhí)行了一次循環(huán),輔助線程捕捉到主線程要求終止的異常,執(zhí)行Thread.ResetAbort退出循環(huán)以便執(zhí)行清理工作。從上面的例子可以清晰的看出控制并發(fā)線程整個的過程。運行結(jié)果如下圖2所示:
線程同步 啟動線程很容易,但是讓他們協(xié)調(diào)工作卻很難,設(shè)計一個多線程的程序時最難的就是計算出并發(fā)的線程會在哪里沖突并用同步邏輯來阻止沖突的發(fā)生。 .NET框架提供了下面的幾個線程同步類: ? AutoResetEvent:阻塞線程直到另一個線程設(shè)置事件 ? Interlocked:以線程安全的方式進(jìn)行簡單操作、如遞增或遞減整數(shù) ? ManualResetEvent:阻塞一個或多個線程直到另一個線程設(shè)置事件 ? Monitor:防止一個以上的線程同時訪問一個資源 ? Mutex:防止一個或多個以上的線程同時訪問一個資源,并能跨越應(yīng)用程序或進(jìn)程的邊界 ? ReaderWriterLock:使多個線程可以同時讀取一個資源,但不允許重疊的讀寫或?qū)懖僮?在以上幾個類里面我們用得最多是Monitor,下面將重點對Monitor類進(jìn)行講解: Monitor的幾個重要的方法: ? Enter:在訪問資源前調(diào)用并在該資源上聲明一個鎖以判斷是否該資源被其他資源所占用,如果是則該線程被阻塞直到可以獲得該資源為止。 ? Exit:在訪問完該資源后調(diào)用以釋放對資源的鎖便于其他線程訪問。 ? Wait:暫時放棄調(diào)用線程對該資源的鎖。 ? Pluse:通知在Wait中阻塞的線程,使得下一個等待線程在當(dāng)前線程釋放鎖后可以運行。 在C#里有l(wèi)ock關(guān)鍵字以取代Monitor的Enter和Exit,在功能上 lock ( SomeResource ) { //您的處理代碼 } 等價于: Monitor.Enter( SomeResource ); try { //您的處理代碼 } finally { Monitor.Exit( ); } 下面的例子向您具體演示一下怎樣用Monitor實現(xiàn)生產(chǎn)者-消費者的問題。表面上看來每個時刻只有一個方法可以執(zhí)行,但是它們卻是并發(fā)執(zhí)行的。首先是Producer得到了鎖,他通過調(diào)用Monitor.Wait阻塞自身,這時Consumer得到了鎖,Consumer調(diào)用Monitor.Pulse使得Producer處于準(zhǔn)備執(zhí)行狀態(tài),然后Consumer調(diào)用Monitor.Wait阻塞自身,這時Producer從Wait調(diào)用中醒來,生成一個資源放入隊列中,調(diào)用Monitor.Pulse使得Consumer從Wait調(diào)用中醒來,Consumer從隊列中取得資源,接下來Consumer通過調(diào)用Monitor.Pulse和Monitor.Wait使得整個進(jìn)程繼續(xù)下去。 class MonitorSample { private Queue _queue = new Queue(); public void Producer() { int counter = 0; lock( _queue )//判斷該資源是否被其他線程占用 { while( counter < 2 ) { Monitor.Wait( _queue );//暫時放棄調(diào)用線程對該資源的鎖,讓Consumer執(zhí)行 _queue.Enqueue( counter );//生成一個資源 Console.WriteLine( String.Format( "生產(chǎn):{0}", counter ) ); Monitor.Pulse( _queue );//通知在Wait中阻塞的Consumer線程即將執(zhí)行 counter++; } } } public void Consumer() { lock( _queue ) { Monitor.Pulse( _queue );//通知在Wait中阻塞的Producer線程即將執(zhí)行 while( Monitor.Wait( _queue, 10 ) ) { int counter = ( int ) _queue.Dequeue();//取出一個資源 Console.WriteLine( String.Format( "消費:{0}", counter ) ); Monitor.Pulse( _queue );//通知在Wait中阻塞的Producer線程即將執(zhí)行 } } } static void Main(string[] args) { MonitorSample monitor = new MonitorSample(); Thread producer = new Thread( new ThreadStart( monitor.Producer ) ); Thread consumer = new Thread( new ThreadStart( monitor.Consumer ) ); producer.Start(); consumer.Start(); producer.Join(); consumer.Join(); Console.ReadLine(); } }
小結(jié) 本文僅僅只是展示了.NET框架強大功能的冰山一角,通過兩個實例具體講解了在.NET框架下開發(fā)多線程程序的必備知識,當(dāng)您熟悉以后應(yīng)該也會認(rèn)為編寫多線程程序是.NET框架里最有趣和有用的東西。
袁劍
.NET 框架與多線程 本文發(fā)表在《程序春秋》2003年12期 摘要 本文介紹了.NET框架的基本概念并簡要的描述了如何利用.NET框架編寫多線程程序。 目錄 ? 概述 ? 功能特性 ? 編程模型 ? 線程概述 ? 線程控制 ? 線程同步 概述 Microsoft.NET代表了一個集合、一個環(huán)境、一個可以作為平臺支持下一代Internet的可編程結(jié)構(gòu),它通過使用HTTP,XML等標(biāo)準(zhǔn),使得各個系統(tǒng)平臺間互操作性成為現(xiàn)實,Microsoft.NET最重要部分是.NET框架,.NET框架是一種新的計算平臺,它簡化了在高度分布式Internet環(huán)境中的應(yīng)用程序開發(fā),它支持超過20種不同的編程語言,它幫助開發(fā)人員把精力集中在實現(xiàn)商業(yè)邏輯的核心上,使開發(fā)人員的經(jīng)驗在面對類型大不相同的應(yīng)用程序(如基于 Windows 的應(yīng)用程序和基于 Web 的應(yīng)用程序)時保持一致,在未來的版本中甚至僅僅在程序發(fā)布時才需要指定發(fā)布的類型(作為Win Form還是Web Form)。 如上圖,.NET框架由2部分組成:公共語言運行時(CLR:是.NET開發(fā)人員的源代碼和硬件底層之間的 中間媒介,所有的.NET 代碼都在CLR中運行)和框架類庫(FCL:包括數(shù)據(jù)訪問組件、基礎(chǔ)類庫以及WebForm、WinForm、Web Services模板)。 功能特性 CLR和FCL緊密結(jié)合在一起,提供了不同系統(tǒng)之間交叉與綜合的解決方案與服務(wù),創(chuàng)造了可控的、安全的、功能豐富的應(yīng)用開發(fā)環(huán)境,以下是它們提供的部分功能。 一次運行,總能運行 所有的開發(fā)人員幾乎都知道“Dll Hell”版本控制問題(當(dāng)新安裝的應(yīng)用程序的組件覆蓋舊有應(yīng)用程序的組件時,導(dǎo)致舊有程序無法正常運行)。為了徹底消除“DLL Hell”現(xiàn)象,.NET框架的結(jié)構(gòu)已與應(yīng)用程序組件隔離,應(yīng)用程序運行時必須加載生成時所用到的組件以確保應(yīng)用程序總是能正常運行。 簡化部署 在.NET框架里軟件安裝的方式是XCOPY,如同在DOS下一樣,只需要將應(yīng)用程序復(fù)制到某個目錄就完成了安裝,卸載應(yīng)用程序只需要刪除目錄。 自動內(nèi)存管理 對于托管資源您再也不必在類里寫析構(gòu)函數(shù)(Finalize)進(jìn)行清理,垃圾管理(GC)可以自動跟蹤資源使用,確保不會產(chǎn)生資源泄漏,實際上GC對Finalize的調(diào)用時間和次序是不確定的。但是微軟建議用戶一定要記得在Dispose 方法里釋放非托管資源如數(shù)據(jù)庫連接、文件等。 類型安全 每個對象都是單根繼承自O(shè)bject(注:也有人認(rèn)為是繼承自Iobject接口)以確保在運行時可以通過調(diào)用GetType方法可以確定對象的類型,通常強制轉(zhuǎn)換為基類型被認(rèn)為是安全的隱式轉(zhuǎn)換。CLR可以驗證所有代碼是否類型安全,類型安全能確??偸且约嫒莸姆绞皆L問被分配對象。 編程模型 以前在Windows平臺下進(jìn)行軟件開發(fā)的C++開發(fā)人員大多使用的是微軟基礎(chǔ)類庫(MFC)或者Win32 APIs,Visual Basic用戶使用的是Visual Basic API,Delphi用戶使用的是Borland公司的VCL,Java用戶使用JDK,彼此之間很難兼容、相互調(diào)用,軟件開發(fā)人員有時也難以取舍,而.NET框架統(tǒng)一了當(dāng)前各種不同的架構(gòu),.NET框架為開發(fā)人員提供了一個統(tǒng)一的、面向?qū)ο蟮?、層次化的、可擴展的框架類庫――FCL,開發(fā)人員不再需要學(xué)習(xí)多種架構(gòu)只須學(xué)習(xí).NET框架就能靈活的采用各種不同的編程語言進(jìn)行開發(fā),.NET框架還實現(xiàn)了跨語言的繼承、錯誤處理、調(diào)試。 在.NET框架里從C#,VB.NET,J#到C++的所有編程語言都是相互平等的,開發(fā)人員可以自由選擇自己喜歡的語言,如下不同語言的程序代碼: C#: class Hello { static void Main()//程序的出口點 { System.Console.Write( "Hello, World!" );//輸出Hello, World! } } VB.NET: Module Hello Sub Main() '程序的出口點 System.Console.Write( "Hello, World!" ) '輸出Hello, World! End Sub End Module 在編譯器上最終生成的都是如下的IL(中間語言)代碼: IL_0000: ldstr "Hello, World!" IL_0005: call void [mscorlib]System.Console::Write(string) IL_000a: ret IL是CLR唯一理解的編程語言,所有的編譯器都將源代碼編譯成IL,IL再被CLR處理。 輸出的結(jié)果是非常熟悉的:Hello, World!。 在.NET框架下您不僅可以開發(fā)傳統(tǒng)的基于Windows平臺下的應(yīng)用,您還可以開發(fā)基于Smart Phone、Pocket PC、Tablet PC等等平臺下的應(yīng)用。 .NET框架提供了強有力的編程模板,可以隨心所欲的編寫WinForm、WebForm、WebService等類型的程序,這些類型的程序的開發(fā)方式與以往有很大的不同,功能也比以往大大加強。其中“最有可能改變世界”的(注:Jeff Prosise語),最令人驚奇的應(yīng)該是Web Form(ASP.NET)。多線程、GDI+、設(shè)計模式、Cache、異常等等這些在以前的Web程序里不敢想象或者很難實現(xiàn)的功能在.NET框架下變得如此的垂手可得。 ASP.NET幾乎天生就是基于MVC模式的,它利用Code-Behind技術(shù)輕而易舉的把頁面(View)和代碼(Model && Control)分離,再加上Page Controller,Distributed,Services等模式,可以把程序結(jié)構(gòu)從傳統(tǒng)的3層擴充到4層、5層甚至更多層,充分滿足開發(fā)大型企業(yè)級應(yīng)用的需要(以后有機會將向大家展示ASP.NET結(jié)合模式開發(fā)令人激動的一面)。利用多線程和GDI+技術(shù)可以一邊顯示文字內(nèi)容、一邊從遠(yuǎn)程抓取圖片并把圖片變換為適當(dāng)?shù)男问?#xff08;如轉(zhuǎn)換為PNG格式,在圖片上記錄版權(quán)信息)顯示給用戶,效率比以往大大提高。 對于相當(dāng)多的人來說,開發(fā)多線程程序是一個相當(dāng)大的挑戰(zhàn),但.NET框架已對其進(jìn)行了相當(dāng)程度的簡化,本文的后面部分將向您介紹多線程編程的基礎(chǔ)知識,并提供一些用于試驗的示例代碼。相信您在看了之后會迅速掌握。 為了便于講解,示例代碼采用的是控制臺程序。 線程概述 線程是CPU時間片分配的單位,不同的線程可以具有不同的優(yōu)先級,每個進(jìn)程至少會有一個主線程。在.NET框架中最基本的執(zhí)行單元是線程,托管代碼是以單線程開始執(zhí)行的,但在執(zhí)行期間可以產(chǎn)生附加的線程來幫助完成指定的任務(wù)。線程分為前臺線程(所有前臺線程都必須退出之后,當(dāng)前進(jìn)程才能退出)和后臺線程(進(jìn)程隨時可以退出,不等待后臺線程退出)。 對于耗時非常長而又不想堵塞界面的操作、服務(wù)器端的應(yīng)用、同時支持多用戶并發(fā)的環(huán)境或者發(fā)揮多處理器的作用的時候都應(yīng)該考慮使用多線程,但是使用線程需要非常謹(jǐn)慎地分析同步情況和線程調(diào)度本身的開銷。 線程控制 線程控制包括線程啟動、掛起、恢復(fù)、休眠、終止等,在下面的這個列子里將會對線程控制做一個大體描述。 public class MyThread { public static void Work() { try { for( int i = 0; i < 4; i++ ) { Console.WriteLine( Thread.CurrentThread.Name + "正在計算" + i.ToString() ); Thread.Sleep( 50 ); } } catch( ThreadAbortException e ) { Console.WriteLine( "錯誤信息:{0}", e.Message ); Thread.ResetAbort();//取消主線程要求中止的請求,如不執(zhí)行則ThreadAbortException會在catch塊末端再次引發(fā) } Console.WriteLine( Thread.CurrentThread.Name + "完成工作!" ); } } class ThreadAbortTest { public static void Main() { Console.WriteLine( "主線程啟動!"); Thread thread = new Thread( new ThreadStart( MyThread.Work ) );//MyThread.Work代表要執(zhí)行的線程函數(shù),它可以是靜態(tài)的,也可以是某個類實例的方法,它是要執(zhí)行的線程函數(shù)的委托 thread.Name = "MyThread"; thread.Start();//線程啟動后將被CPU調(diào)度,但不一定是馬上執(zhí)行,所以同樣的例子在不同的機器上可能會有不同的結(jié)果。 Console.WriteLine( "主線程第一次休眠!"); Thread.Sleep( 100 ); Console.WriteLine( "MyThread被掛起!"); thread.Suspend();//掛起子線程 Console.WriteLine( "主線程第二次休眠!"); Thread.Sleep( 100 ); Console.WriteLine( "MyThread被恢復(fù)!"); thread.Resume();//恢復(fù)子線程 thread.Abort();//終止子線程 thread.Join();//直到到子線程完全終止了,主線程才繼續(xù)運行 Console.WriteLine( "主線程終止!" ); Console.ReadLine(); } } 程序啟動后會創(chuàng)建一個名為MyThread的輔助線程并通過調(diào)用thread.Start啟動它,然后調(diào)用Thread.Sleep( 100 )休眠100微妙,這時輔助線程一直在運行,接下來主線程調(diào)用thread.Suspend掛起輔助線程并再休眠100微妙后再調(diào)用Thread.Sleep恢復(fù)輔助線程,在被掛起和被恢復(fù)這段時間內(nèi)輔助線程被阻塞,緊跟著主線程執(zhí)行thread.Abort方法終止輔助線程并執(zhí)行thread.Join等待輔助線程結(jié)束,在輔助線程接收到終止請求時它已經(jīng)工作并又執(zhí)行了一次循環(huán),輔助線程捕捉到主線程要求終止的異常,執(zhí)行Thread.ResetAbort退出循環(huán)以便執(zhí)行清理工作。從上面的例子可以清晰的看出控制并發(fā)線程整個的過程。運行結(jié)果如下圖2所示:
線程同步 啟動線程很容易,但是讓他們協(xié)調(diào)工作卻很難,設(shè)計一個多線程的程序時最難的就是計算出并發(fā)的線程會在哪里沖突并用同步邏輯來阻止沖突的發(fā)生。 .NET框架提供了下面的幾個線程同步類: ? AutoResetEvent:阻塞線程直到另一個線程設(shè)置事件 ? Interlocked:以線程安全的方式進(jìn)行簡單操作、如遞增或遞減整數(shù) ? ManualResetEvent:阻塞一個或多個線程直到另一個線程設(shè)置事件 ? Monitor:防止一個以上的線程同時訪問一個資源 ? Mutex:防止一個或多個以上的線程同時訪問一個資源,并能跨越應(yīng)用程序或進(jìn)程的邊界 ? ReaderWriterLock:使多個線程可以同時讀取一個資源,但不允許重疊的讀寫或?qū)懖僮?在以上幾個類里面我們用得最多是Monitor,下面將重點對Monitor類進(jìn)行講解: Monitor的幾個重要的方法: ? Enter:在訪問資源前調(diào)用并在該資源上聲明一個鎖以判斷是否該資源被其他資源所占用,如果是則該線程被阻塞直到可以獲得該資源為止。 ? Exit:在訪問完該資源后調(diào)用以釋放對資源的鎖便于其他線程訪問。 ? Wait:暫時放棄調(diào)用線程對該資源的鎖。 ? Pluse:通知在Wait中阻塞的線程,使得下一個等待線程在當(dāng)前線程釋放鎖后可以運行。 在C#里有l(wèi)ock關(guān)鍵字以取代Monitor的Enter和Exit,在功能上 lock ( SomeResource ) { //您的處理代碼 } 等價于: Monitor.Enter( SomeResource ); try { //您的處理代碼 } finally { Monitor.Exit( ); } 下面的例子向您具體演示一下怎樣用Monitor實現(xiàn)生產(chǎn)者-消費者的問題。表面上看來每個時刻只有一個方法可以執(zhí)行,但是它們卻是并發(fā)執(zhí)行的。首先是Producer得到了鎖,他通過調(diào)用Monitor.Wait阻塞自身,這時Consumer得到了鎖,Consumer調(diào)用Monitor.Pulse使得Producer處于準(zhǔn)備執(zhí)行狀態(tài),然后Consumer調(diào)用Monitor.Wait阻塞自身,這時Producer從Wait調(diào)用中醒來,生成一個資源放入隊列中,調(diào)用Monitor.Pulse使得Consumer從Wait調(diào)用中醒來,Consumer從隊列中取得資源,接下來Consumer通過調(diào)用Monitor.Pulse和Monitor.Wait使得整個進(jìn)程繼續(xù)下去。 class MonitorSample { private Queue _queue = new Queue(); public void Producer() { int counter = 0; lock( _queue )//判斷該資源是否被其他線程占用 { while( counter < 2 ) { Monitor.Wait( _queue );//暫時放棄調(diào)用線程對該資源的鎖,讓Consumer執(zhí)行 _queue.Enqueue( counter );//生成一個資源 Console.WriteLine( String.Format( "生產(chǎn):{0}", counter ) ); Monitor.Pulse( _queue );//通知在Wait中阻塞的Consumer線程即將執(zhí)行 counter++; } } } public void Consumer() { lock( _queue ) { Monitor.Pulse( _queue );//通知在Wait中阻塞的Producer線程即將執(zhí)行 while( Monitor.Wait( _queue, 10 ) ) { int counter = ( int ) _queue.Dequeue();//取出一個資源 Console.WriteLine( String.Format( "消費:{0}", counter ) ); Monitor.Pulse( _queue );//通知在Wait中阻塞的Producer線程即將執(zhí)行 } } } static void Main(string[] args) { MonitorSample monitor = new MonitorSample(); Thread producer = new Thread( new ThreadStart( monitor.Producer ) ); Thread consumer = new Thread( new ThreadStart( monitor.Consumer ) ); producer.Start(); consumer.Start(); producer.Join(); consumer.Join(); Console.ReadLine(); } }
小結(jié) 本文僅僅只是展示了.NET框架強大功能的冰山一角,通過兩個實例具體講解了在.NET框架下開發(fā)多線程程序的必備知識,當(dāng)您熟悉以后應(yīng)該也會認(rèn)為編寫多線程程序是.NET框架里最有趣和有用的東西。
轉(zhuǎn)載于:https://www.cnblogs.com/zhuor/archive/2006/04/10/370983.html
總結(jié)
以上是生活随笔為你收集整理的.NET 框架与多线程 (转载)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Common FileUpload组件的
- 下一篇: NHibernate1.02使用MsAc