[多線程]windows線程小結

來源:互聯網
上載者:User

線程同步是一個非常大的話題,包括方方面面的內容。從大的方面講,線程的同步可分使用者模式的線程同步和核心對象的線程同步兩大類。使用者模式中線程的同步方法主要有原子訪問和臨界區等方法。其特點是同步速度特別快,適合於對線程運行速度有嚴格要求的場合。
  核心對象的線程同步則主要由事件、等待定時器、訊號量以及號誌等核心對象構成。由於這種同步機制使用了核心對象,使用時必須將線程從使用者模式切換到核心模式,而這種轉換一般要耗費近千個CPU周期,因此同步速度較慢,但在適用性上卻要遠優於使用者模式的線程同步方式。     

編程簡便的線程進程式控制制手段。      

  • 臨界區:通過對多線程的序列化來訪問公用資源或一段代碼,速度快,適合控制資料訪問。 
  • 互斥量:為協調共同對一個共用資源的單獨訪問而設計的。 
  • 訊號量:為控制一個具有有限數量使用者資源而設計。 
  • 事 件:用來通知線程有一些事件已發生,從而啟動後繼任務的開始。 

臨界區(Critical Section) 

    保證在某一時刻只有一個線程能訪問資料的簡便辦法。在任意時刻只允許一個線程對共用資源進行訪問。如果有多個線程試圖同時訪問臨界區,那麼在有一個線程進入後其他所有試圖訪問此臨界區的線程將被掛起,並一直持續到進入臨界區的線程離開。臨界區在被釋放後,其他線程可以繼續搶佔,並以此達到用原子方式操作共用資源的目的。 
    臨界區包含兩個操作原語: 

  • EnterCriticalSection() 進入臨界區 
  • LeaveCriticalSection() 離開臨界區 

    EnterCriticalSection()語句執行後代碼將進入臨界區以後無論發生什麼,必須確保與之匹配的LeaveCriticalSection()都能夠被執行到。否則臨界區保護的共用資源將永遠不會被釋放。雖然臨界區同步速度很快,但卻只能用來同步本進程內的線程,而不可用來同步多個進程中的線程。 

互斥量(Mutex) 

    互斥量跟臨界區很相似,只有擁有互斥對象的線程才具有訪問資源的許可權,由於互斥對象只有一個,因此就決定了任何情況下此共用資源都不會同時被多個線程所訪問。當前佔據資源的線程在任務處理完後應將擁有的互斥對象交出,以便其他線程在獲得後得以訪問資源。互斥量比臨界區複雜。因為使用互斥不僅僅能夠在同一應用程式不同線程中實現資源的安全共用,而且可以在不同應用程式的線程之間實現對資源的安全共用。 
    互斥量包含的幾個操作原語: 

  •     CreateMutex() 建立一個互斥量 
  •     OpenMutex() 開啟一個互斥量 
  •     ReleaseMutex() 釋放互斥量 
  •     WaitForSingelObjects() 等待互斥量對象 
訊號量(Semaphores) 

    訊號量對象對線程的同步方式與前面幾種方法不同,訊號允許多個線程同時使用共用資源,這與作業系統中的PV操作相同。它指出了同時訪問共用資源的線程最大數目。它允許多個線程在同一時刻訪問同一資源,但是需要限制在同一時刻訪問此資源的最大線程數目。在用CreateSemaphore()建立訊號量時即要同時指出允許的最大資源計數和當前可用資源計數。一般是將當前可用資源計數設定為最大資源計數,每增加一個線程對共用資源的訪問,當前可用資源計數就會減1,只要當前可用資源計數是大於0的,就可以發出訊號量訊號。但是當前可用計數減小到0時則說明當前佔用資源的線程數已經達到了所允許的最大數目,不能在允許其他線程的進入,此時的訊號量訊號將無法發出。線程在處理完共用資源後,應在離開的同時通過ReleaseSemaphore()函數將當前可用資源計數加1。在任何時候當前可用資源計數決不可能大於最大資源計數。 
    PV操作及訊號量的概念都是由荷蘭科學家E.W.Dijkstra提出的。訊號量S是一個整數,S大於等於零時代表可供並發進程使用的資源實體數,但S小於零時則表示正在等待使用共用資源的進程數。 
    P操作申請資源: 
    (1)S減1; 
    (2)若S減1後仍大於等於零,則進程繼續執行; 
    (3)若S減1後小於零,則該進程被阻塞後進入與該訊號相對應的隊列中,然後轉入進程調度。 
   
    V操作 釋放資源: 
    (1)S加1; 
    (2)若相加結果大於零,則進程繼續執行; 
    (3)若相加結果小於等於零,則從該訊號的等待隊列中喚醒一個等待進程,然後再返回原進程繼續執行或轉入進程調度。 

    訊號量包含的幾個操作原語: 

  •     CreateSemaphore() 建立一個訊號量 
  •     OpenSemaphore() 開啟一個訊號量 
  •     ReleaseSemaphore() 釋放訊號量 
  •     WaitForSingleObject() 等待訊號量

事件(Event) 

    事件對象也可以通過通知操作的方式來保持線程的同步。並且可以實現不同進程中的線程同步操作。 
    訊號量包含的幾個操作原語: 

  •     CreateEvent() 建立一個訊號量 
  •     OpenEvent() 開啟一個事件 
  •     SetEvent() 回置事件 
  •     WaitForSingleObject() 等待一個事件 
  •     WaitForMultipleObjects() 等待多個事件 
總結: 

    1. 互斥量與臨界區的作用非常相似,但互斥量是可以命名的,也就是說它可以跨越進程使用。所以建立互斥量需要的資源更多,所以如果只為了在進程內部是用的話使用臨界區會帶來速度上的優勢並能夠減少資源佔用量。因為互斥量是跨進程的互斥量一旦被建立,就可以通過名字開啟它。 
    2. 互斥量(Mutex),號誌(Semaphore),事件(Event)都可以被跨越進程使用來進行同步資料操作,而其他的對象與資料同步操作無關,但對於進程和線程來講,如果進程和線程在運行狀態則為無訊號狀態,在退出後為有訊號狀態。所以可以使用WaitForSingleObject來等待進程和線程退出。 

在windows平台下,用於對多線程(包括進程)之間的同步保護機制,基本上有這麼幾種:
1)Critical Section對象 2)Event對象 3)Mutex對象 4) Semaphore對象。 

以下我們所討論的這些行為特徵,是對並發的進/線程之間的同步保護機制的一般描述,本文用windows平台作為一個典型的例子。 基於這一些行為特徵,對本文提及的這四種同步對象做一個分類。另外,在這裡,我們把這四種同步對象,統統稱為“鎖”,以便於接下來的討論。

第一、保護與同步。

在這裡要強調的是:保護與同步是兩個不同的概念。而我們經常會混合這兩個概念。保護是指在多線程的環境下對共用資源的保護。這樣的共用資源大多數情況下是一段記憶體塊,它會被很多線程試圖訪問和修改。而同步更多的強調的是線程之間的協作,協同工作是需要同步支援的。
基於這一性質,我們可以看出:Critical Section對象其本質更多的強調的是保護,而Event對象、Mutex對象與Semaphore對象更多的強調的是同步。不過,這樣的區別,只是概念上的區別,其本身不會對程式本身產生影響。
第二、鎖的等待逾時

在開發並發的多進/線程程式時,為了避免死結之類的問題,引入了“等逾時“的概念,即當一個線程需要獲得一個鎖來執行某些代碼的時候,它可以在所等待的鎖上設定逾時值。如果在確定的時間(逾時值)內無法獲得該鎖,它可以選擇放棄執行該段代碼的權利,這樣可以在一定程度上避免出現死結的問題。這就是鎖的等待逾時的基本含義。基於這一行為特徵,我們來對上面四種同步對象做一個劃分:Critical Section對象是無法設定等待逾時的,而其他三個對象則可以設定等待逾時。從這一點來講,在使用Critical Section對象時,由於在等待進入關鍵程式碼片段時無法設定等待逾時,很容易造成死結。
第三、線程鎖與進程鎖

這裡所說的線程鎖指的是該鎖只在一個進程的所有線程中可見,而進程鎖指的是該鎖可以被不同的進程所訪問,可用於進程間的同步與互斥。當然進程鎖仍然可以被用於同一個進程的不同線程之間的同步與互斥。進程鎖的概念是大於線程鎖的。基於這一特點劃分的話,Critical Section對象是線程鎖,而其他三個對象是進程鎖。這一點從本質上來分析,Critical Section對象是使用者態模式下面實現線程同步的方法,而其他三個對象均是核心對象。核心對象機制的適應性遠遠優於使用者方式機制。實際上,核心對象機制的唯一不足之處在於它的速度比較慢,這是因為當調用核心機制對象時,必須從使用者方式轉到核心方式。這樣的轉換需要付出很大的代價,是一件很費時的操作。在X86平台上,這樣往返一次需要佔用1000個CPU周期(這並不包括執行核心方式的代碼)。當然需要注意的是:使用Critical Section對象並不意味著線程不會陷入核心態執行。當一個線程試圖進入另一個線程擁有的關鍵程式碼片段時,該線程就會進入等待狀態。這意味著:該線程必須從使用者態轉為核心態。(為了提高這一方面的效能,Microsoft將迴圈鎖的概念納入到了Critical Section對象中,該線程可以有選擇地不進入核心態等待.具體請參閱MSDN)
第四、鎖的遞迴特質

所謂遞迴鎖指的是當一個線程擁有一個同步鎖時,而遞迴地想再次取得該鎖.如果這次獲得操作不會阻塞當前線程的執行,則稱該鎖為遞迴鎖.遞迴鎖主要是在"保護"的概念上提出的,而"保護"概念下的鎖包括Critical Section對象和Mutext 對象.這兩種鎖在Windows平台上都是遞迴鎖。需要注意的是:調用線程獲得幾次遞迴鎖必須釋放幾次遞迴鎖。
第五、讀寫鎖

讀寫鎖允許高效的並發的訪問多線程環境下的共用資源。對於一種共用資源,多個線程可以獲得讀鎖,共用地讀該共用資源。而在同一時刻,只允許一個線程擁有寫鎖改變該共用資源.這就是讀寫鎖的概念。很遺憾的是在Windows平台上沒有這樣的讀寫鎖,你需要自己去實現。
對以上總結

個人認為,如果你想深入研究多線程的同步機制,ACE是一個絕佳的教材,在這裡,你會看到什麼是Scoped Lock, 讀寫鎖如何?等等。 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.