C#多線程整理

什麼是進程?

當一個程序開始運行時,它就是一個進程,進程包括運行中的程序和程序所使用到的內存和系統資源。
而一個進程又是由多個線程所組成的。

什麼是線程?
線程是程序中的一個執行流,每個線程都有自己的專有寄存器(棧指針、程序計數器等)但代碼區是共享的,即不同的線程可以執行同樣的函數。

什麼是多線程?
多線程是指程序中包含多個執行流,即在一個程序中可以同時運行多個不同的線程來執行不同的任務,也就是說允許單個程序創建多個並行執行的線程來完成各自的任務。

多線程的好處:
可以提高CPU的利用率。在多線程程序中,一個線程必須等待的時候,CPU可以運行其它的線程而不是等待,這樣就大大提高了程序的效率。 

多線程的不利方面:
線程也是程序,所以線程需要佔用內存,線程越多佔用內存也越多; 
多線程需要協調和管理,所以需要CPU時間跟蹤線程; 
線程之間對共享資源的訪問會相互影響,必須解決競用共享資源的問題;

線程太多會導致控制太複雜,最終可能造成很多Bug; 

 ref:http://www.cnblogs.com/xugang/archive/2008/04/06/1138856.html 

 

主線程Main()函數

所有線程都是依附於Main()函數所在的線程的,Main()函數是C#程序的入口,起始線程可以稱之爲主線程。
如果所有的前臺線程都停止了,那麼主線程可以終止,而所有的後臺線程都將無條件終止。

所有的線程雖然在微觀上是串行執行的,但是在宏觀上你完全可以認爲它們在並行執行。

 線程的優先級

當線程之間爭奪CPU時間時,CPU 是按照線程的優先級給予服務的。在C#應用程序中,用戶可以設定5個不同的優先級,由高到低分別是Highest,AboveNormal,Normal,BelowNormal,Lowest,在創建線程時如果不指定優先級,那麼系統默認爲ThreadPriority.Normal。


ref:http://www.cnblogs.com/xugang/archive/2008/04/06/1138841.html 

 

前面說過,每個線程都有自己的資源,但是代碼區是共享的,即每個線程都可以執行相同的函數。這可能帶來的問題就是幾個線程同時執行一個函數,導致數據的混亂,產生不可預料的結果,因此我們必須避免這種情況的發生。

 C#提供了一個關鍵字lock,它可以把一段代碼定義爲互斥段(critical section),互斥段在一個時刻內只允許一個線程進入執行,而其他線程必須等待。

Monitor 類鎖定一個對象

當多線程公用一個對象時,也會出現和公用代碼類似的問題,這種問題就不應該使用lock關鍵字了,這裏需要用到System.Threading中的一個類Monitor,我們可以稱之爲監視器,Monitor提供了使線程共享資源的方案。

  Monitor類可以鎖定一個對象,一個線程只有得到這把鎖纔可以對該對象進行操作。對象鎖機制保證了在可能引起混亂的情況下一個時刻只有一個線程可以訪問這個對象。

Monitor必須和一個具體的對象相關聯,但是由於它是一個靜態的類,所以不能使用它來定義對象,而且它的所有方法都是靜態的,不能使用對象來引用。 

如上所示,當一個線程調用Monitor.Enter()方法鎖定一個對象時,這個對象就歸它所有了,其它線程想要訪問這個對象,只有等待它使用Monitor.Exit()方法釋放鎖。爲了保證線程最終都能釋放鎖,你可以把Monitor.Exit()方法寫在try-catch-finally結構中的finally代碼塊裏。 

對於任何一個被Monitor鎖定的對象,內存中都保存着與它相關的一些信息:
其一是現在持有鎖的線程的引用;
其二是一個預備隊列,隊列中保存了已經準備好獲取鎖的線程;
其三是一個等待隊列,隊列中保存着當前正在等待這個對象狀態改變的隊列的引用。

當擁有對象鎖的線程準備釋放鎖時,它使用Monitor.Pulse()方法通知等待隊列中的第一個線程,於是該線程被轉移到預備隊列中,當對象鎖被釋放時,在預備隊列中的線程可以立即獲得對象鎖。

 

 ref:http://www.cnblogs.com/xugang/archive/2008/03/23/1118594.html

 

在多線程的程序中,經常會出現兩種情況:

一種情況:   應用程序中,線程把大部分的時間花費在等待狀態,等待某個事件發生,然後才能給予響應
                  這一般使用ThreadPool(線程池)來解決;

另一種情況:線程平時都處於休眠狀態,只是週期性地被喚醒,這一般使用Timer(定時器)來解決; 

 ThreadPool類提供一個由系統維護的線程池(可以看作一個線程的容器),該容器需要 Windows 2000 以上系統支持,因爲其中某些方法調用了只有高版本的Windows纔有的API函數。

將線程安放在線程池裏,需使用ThreadPool.QueueUserWorkItem()方法,該方法的原型如下:

//將一個線程放進線程池,該線程的Start()方法將調用WaitCallback代理對象代表的函數
public static bool QueueUserWorkItem(WaitCallback);

//重載的方法如下,參數object將傳遞給WaitCallback所代表的方法

public static bool QueueUserWorkItem(WaitCallback, object);

注意: 

ThreadPool類是一個靜態類,你不能也不必要生成它的對象。而且一旦使用該方法在線程池中添加了一個項目,那麼該項目將是無法取消的。

在這裏你無需自己建立線程,只需把你要做的工作寫成函數,然後作爲參數傳遞給ThreadPool.QueueUserWorkItem()方法就行了,傳遞的方法就是依靠WaitCallback代理對象,而線程的建立、管理、運行等工作都是由系統自動完成的,你無須考慮那些複雜的細節問題。 

 ThreadPool 的用法:

首先程序創建了一個ManualResetEvent對象,該對象就像一個信號燈,可以利用它的信號來通知其它線程。
本例中,當線程池中所有線程工作都完成以後,ManualResetEvent對象將被設置爲有信號,從而通知主線程繼續運行。

ManualResetEvent對象有幾個重要的方法:
初始化該對象時,用戶可以指定其默認的狀態(有信號/無信號);
在初始化以後,該對象將保持原來的狀態不變,直到它的Reset()或者Set()方法被調用:
Reset()方法:將其設置爲無信號狀態;
Set()方法:將其設置爲有信號狀態。
WaitOne()方法:使當前線程掛起,直到ManualResetEvent對象處於有信號狀態,此時該線程將被激活。然後,程序將向線程池中添加工作項,這些以函數形式提供的工作項被系統用來初始化自動建立的線程。當所有的線程都運行完了以後,ManualResetEvent.Set()方法被調用,因爲調用了ManualResetEvent.WaitOne()方法而處在等待狀態的主線程將接收到這個信號,於是它接着往下執行,完成後邊的工作。

 

ref:http://www.cnblogs.com/xugang/archive/2008/03/23/1118584.html 

 

Timer類:設置一個定時器,定時執行用戶指定的函數。
              定時器啓動後,系統將自動建立一個新的線程,執行用戶指定的函數。

初始化一個Timer對象: 
Timer timer = new Timer(timerDelegate, s,1000, 1000); 

// 第一個參數:指定了TimerCallback 委託,表示要執行的方法;
// 第二個參數:一個包含回調方法要使用的信息的對象,或者爲空引用;

// 第三個參數:延遲時間——計時開始的時刻距現在的時間,單位是毫秒,指定爲“0”表示立即啓動計時器;

// 第四個參數:定時器的時間間隔——計時開始以後,每隔這麼長的一段時間,TimerCallback所代表的方法將被調用一次,單位也是毫秒。指定 Timeout.Infinite 可以禁用定期終止。

Timer.Change()方法:修改定時器的設置。(這是一個參數類型重載的方法) 

 

 ref:http://www.cnblogs.com/xugang/archive/2008/03/23/1118537.html

 如何控制好多個線程相互之間的聯繫,不產生衝突和重複,這需要用到互斥對象,即:System.Threading 命名空間中的 Mutex 類。

我們可以把Mutex看作一個出租車,乘客看作線程。乘客首先等車,然後上車,最後下車。當一個乘客在車上時,其他乘客就只有等他下車以後纔可以上車。而線程與Mutex對象的關係也正是如此,線程使用Mutex.WaitOne()方法等待Mutex對象被釋放,如果它等待的Mutex對象被釋放了,它就自動擁有這個對象,直到它調用Mutex.ReleaseMutex()方法釋放這個對象,而在此期間,其他想要獲取這個Mutex對象的線程都只有等待。

下面這個例子使用了Mutex對象來同步四個線程,主線程等待四個線程的結束,而這四個線程的運行又是與兩個Mutex對象相關聯的。

其中還用到AutoResetEvent類的對象,可以把它理解爲一個信號燈。這裏用它的有信號狀態來表示一個線程的結束。

 

ref:http://www.cnblogs.com/xugang/archive/2008/03/23/1118530.html

 

--------------------------------------------------------------------------------------------------------------------------------------

C#多線程學習系列:

C#多線程學習(一) 多線程的相關概念

C#多線程學習(二) 如何操縱一個線程
http://www.cnblogs.com/xugang/archive/2008/04/06/1138841.html

 

C#多線程學習(三) 生產者和消費者
http://www.cnblogs.com/xugang/archive/2008/03/23/1118594.html

 

C#多線程學習(四) 多線程的自動管理(線程池)
http://www.cnblogs.com/xugang/archive/2008/03/23/1118584.html

 

C#多線程學習(五) 多線程的自動管理(定時器)
http://www.cnblogs.com/xugang/archive/2008/03/23/1118537.html

 

C#多線程學習(六) 互斥對象
http://www.cnblogs.com/xugang/archive/2008/03/23/1118530.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章