淺談.net多線程機制


最近由於工作需要,對多線程進行了深入研究,也只能略知一二,尚不能融會貫通。如有不妥之處,還請大牛們不吝賜教。

本文不會詳細列出各種多線程的例子和源代碼。本文旨在給那些和我當初對多線程理不清頭緒的人投石問路。

一、多線程原理:

Windows是一個多任務的系統,當一個程序開始運行時,它就是一個進程,進程所指包括運行中的程序和程序所使用到的內存和系統資源。而一個進程又是由多個線程所組成的,線程是程序中的一個執行流,每個線程都有自己的專有寄存器(棧指針、程序計數器等),但代碼區是共享的,即不同的線程可以執行同樣的函數。多線程是指程序中包含多個執行流,即在一個程序中可以同時運行多個不同的線程來執行不同的任務,也就是說允許單個程序創建多個並行執行的線程來完成各自的任務。

二、多線程分類:

1. Critical section:臨界區

2. Mutex:互斥

3.Event:事件

4.線程池

園子里很多關於多線程的文章都只是片面的只介紹其中一種實現方法,並沒有給出全貌,往往讓我們感覺摸不着頭腦。

其實在.NET中,也就只有以上四種機制,這四種機制,分別都有實現,有些還不止一種實現。

 

1.首先說一下“Critical section”: 臨界區顧名思義就是一塊不能並發訪問的區域,同一時刻只能有一個線程占有它。

它的實現有:

a. Lock:

有可能多個線程共用同一個函數.想象一下:如果同一個函數被多個線程同事執行會是什么后果?但是如果你使用了Lock機制,就可以避免。

但是Lock也不能亂用,因為容易發生死鎖。

b.Monitor:

共用對象互斥,多個線程共用同一個對象。原理和Lock有異曲同工之妙,有時他們的應用場景是一樣的。

Queue oQueue=new Queue();
Monitor.Enter(oQueue);//現在oQueue對象只能被當前線程操縱了
Monitor.Exit(oQueue);//釋放鎖
為了保證線程最終都能釋放鎖,你可以把Monitor.Exit()方法寫在try-catch-finally結構中的finally代碼塊里。
當擁有對象鎖的線程准備釋放鎖時,它使用Monitor.Pulse()方法通知等待隊列中的第一個線程,於是該線程被轉移到預備隊列中,當對象鎖被釋放時,在預備隊列中的線程可以立即獲得對象鎖。

多謝浪雪,讓我明白了Lock其實就是Monitor的便捷語法。以前只知道他們功能極其相似,慚愧。。

2.Mutex

一個同步基元,也可用於進程間同步。你可以把它想象成一個令牌,只有獲得該令牌的線程才有權訪問資源,否則只能等待。
當兩個或更多線程需要同時訪問一個共享資源時,系統需要使用同步機制來確保一次只有一個線程使用該資源。 Mutex 是同步基元,它只向一個線程授予對共享資源的獨占訪問權。 如果一個線程獲取了互斥體,則要獲取該互斥體的第二個線程將被掛起,直到第一個線程釋放該互斥體。

Thread.Suspend,Thread.Resume已經過時了,這個大家應該都知道吧?其實使用Mutex很容易就實現了。

Thread.Suspend:就是收回令牌,令所有的線程都等待(暫停),Thread.Resume就是將令牌歸還。

 

個人覺得介紹Mutex比較好的的文章:  http://www.cnblogs.com/city22/archive/2007/02/02/638260.html#2349012

以上是摘抄:

Mutex是一個令牌,當一個線程拿到這個令牌時運行,另外想拿到令牌的線程就必須等待,直到拿到令牌的線程釋放令牌。沒有所有權的線程是無法釋放令牌的。

 Mutex(false,”string”)中的string是令牌的關鍵,或者可以叫令牌名,因為Mutex是跨進程的,整個系統中只會有唯一的令牌存在所以,也就是說你在一個應用程序中的一個線程中得到了Mutex的所有權,那在另外一個線程中的另外的線程想得到他就必須要等待。

要弄清楚Mutex就還需要弄清楚兩個很重要的問題:

1.那就是Mutex是調用的Win32 的API

HANDLE CreateMutex(

   LPSECURITY_ATTRIBUTES lpMutexAttributes,

   BOOL bInitialOwner,

   LPCTSTR lpName

);

這就是他為什么能跨進程訪問的原因,正是由於它使用P/Invoke,他的效率問題就凸現出來,明顯不如Monitor之類的快,用的時候還需多多斟酌。

3.Event

按照我的理解,它和Mutext區別在於:實現方式不一樣。Mutext是靠一個基元,而Event是靠事件通知。

它包含:

AutoRestEvent: http://msdn.microsoft.com/zh-cn/library/system.threading.autoresetevent.aspx

ManualResetEvent: http://msdn.microsoft.com/zh-cn/library/system.threading.manualresetevent(v=VS.80).aspx

AutoResetEvent與ManualResetEvent的區別大家可以自己去找,因為自己不是很了解,不敢亂說。

但是AutoResetEvent的效率要高些,而ManualResetEvent更靈活一些。

4.線程池(ThreadPool)

提供一個線程池,該線程池可用於執行任務、發送工作項、處理異步 I/O、代表其他線程等待以及處理計時器。

許多應用程序創建的線程都要在休眠狀態中消耗大量時間,以等待事件發生。 其他線程可能進入休眠狀態,只被定期喚醒以輪詢更改或更新狀態信息。 線程池通過為應用程序提供一個由系統管理的輔助線程池,使您可以更為有效地使用線程。

http://msdn.microsoft.com/zh-cn/library/system.threading.threadpool.aspx

說到ThreadPool不得不說Semaphore(信號燈,旗語)

它是最高效的多線程控制方法,因為它是限制可同時訪問某一資源或資源池的線程數。也就是說,你可以讓多個線程“同時訪問”一個臨界資源。雖然這樣講不對,但是你可以這么理解。

 

 5.拿不准:

關於線程池還有一個不得不提:System.Threading.Timer ,它是是一個簡單的輕量計時器,它使用回調方法並由線程池線程提供服務。

http://msdn.microsoft.com/zh-cn/library/system.threading.timer.aspx

 

還有其它的,請補充。

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM