windows多線程同步

來源:互聯網
上載者:User
概述

  任何單個應用程式都不能完全使該處理器達到滿負荷。當一個線程遇到較長等待時間事件時,同步多線程還允許另一線程中的指令使用所有執行單元。例如,當一個線程發生快取不命中,另一個線程可以繼續執行。同步多線程是 POWER5 和 POWER6 處理器的功能,可與共用處理器配合使用。

 

  SMT 對於商業交易處理負載的效能最佳化可達30%。在更加註重系統的整體輸送量而非單獨線程的輸送量時,SMT 是一個很好地選擇。

 

  但是並非所有的應用都能通過SMT 取得效能最佳化。那些效能受到執行單元限制的應用,或者那些耗盡所有處理器的記憶體頻寬的應用,其效能都不會通過在同一個處理器上執行兩個線程而得到提高。

 

  儘管SMT 可以使系統識別到雙倍於物理CPU數量的邏輯CPU(lcpu),但是這並不意味著系統擁有了兩倍的CPU能力。

 

  SMT技術允許核心在同一時間運行兩個不同的進程,以此來壓縮多任務處理時所需要的總時間。這麼做有兩個好處,其一是提高處理器的計算效能,減少使用者得到結果所需的時間;其二就是更好的能效表現,利用更短的時間來完成任務,這就意味著在剩下的時間裡節約更多的電能消耗。當然這麼做有一個總前提——保證SMT不會重複HT所犯的錯誤,而提供這個擔保的則是在酷睿微架構中表現非常出色的分支預測設計。[1]

 編輯本段同步多線程的同步機制

  1、 Event

 

  用事件(Event)來同步線程是最具彈性的了。一個事件有兩種狀態:激髮狀態和未激髮狀態。也稱有訊號狀態和無訊號狀態。事件又分兩種類型:手動重設事件和自動重設事件。手動重設事件被設定為激髮狀態後,會喚醒所有等待的線程,而且一直保持為激髮狀態,直到程式重新把它設定為未激髮狀態。自動重設事件被設定為激髮狀態後,會喚醒“一個”等待中的線程,然後自動回復為未激髮狀態。所以用自動重設事件來同步兩個線程比較理想。MFC中對應的類為CEvent.。CEvent的建構函式預設建立一個自動重設的事件,而且處於未激髮狀態。共有三個函數來改變事件的狀態:SetEvent,ResetEvent和PulseEvent。用事件來同步線程是一種比較理想的做法,但在實際的使用過程中要注意的是,對自動重設事件調用SetEvent和PulseEvent有可能會引起死結,必須小心。

 

  多線程同步-event

 

  在所有的核心對象中,事件核心對象是個最基本的。它包含一個使用計數(與所有核心對象一樣),一個BOOL值(用於指明該事件是個自動重設的事件還是一個人工重設的事件),還有一個BOOL值(用於指明該事件處於已通知狀態還是未通知狀態)。事件能夠通知一個線程的操作已經完成。有兩種類型的事件對象。一種是人工重設事件,另一種是自動重設事件。他們不同的地方在於:當人工重設的事件得到通知時,等待該事件的所有線程均變為可調度線程。當一個自動重設的事件得到通知時,等待該事件的線程中只有一個線程變為可調度線程。

 

  當一個線程執行初始化操作,然後通知另一個線程執行剩餘的操作時,事件使用得最頻繁。在這種情況下,事件初始化為未通知狀態,然後,當該線程完成它的初始化操作後,它就將事件設定為已通知狀態,而一直在等待該事件的另一個線程在事件已經被通知後,就變成可調度線程。

 

  當這個進程啟動時,它建立一個人工重設的未通知狀態的事件,並且將控制代碼儲存在一個全域變數中。這使得該進程中的其他線程能夠非常容易地訪問同一個事件對象。程式一開始建立了三個線程,這些線程在初始化後就被掛起,等待事件。這些線程要等待檔案的內容讀入記憶體,然後每個線程都會訪問這段檔案內容。一個線程進行單詞計數,另一個線程運行拼字檢查,第三個線程運行語法檢查。這3個線程函數的代碼的開始部分都相同,每個函數都調用WaitForSingleObject.,這將使線程暫停運行,直到檔案的內容由主線程讀入記憶體為止。一旦主線程將資料準備好,它就調用SetEvent,給事件發出通知訊號。這時,系統就使所有這3個輔助線程進入可調度狀態,它們都獲得了C P U時間,並且可以訪問記憶體塊。這3個線程都必須以唯讀方式訪問記憶體,否則會出現記憶體錯誤。這就是所有3個線程能夠同時啟動並執行唯一原因。如果電腦上配有三個以上CPU,理論上這個3個線程能夠真正地同時運行,從而可以在很短的時間內完成大量的操作

 

  如果你使用自動重設的事件而不是人工重設的事件,那麼應用程式的行為特性就有很大的差別。當主線程調用S e t E v e n t之後,系統只允許一個輔助線程變成可調度狀態。同樣,也無法保證系統將使哪個線程變為可調度狀態。其餘兩個輔助線程將繼續等待。已經變為可調度狀態的線程擁有對記憶體塊的獨佔訪問權。

 

  讓我們重新編寫線程的函數,使得每個函數在返回前調用S e t E v e n t函數(就像Wi n M a i n函數所做的那樣)。

 

  當主線程將檔案內容讀入記憶體後,它就調用SetEvent函數,這樣作業系統就會使這三個在等待的線程中的一個成為可調度線程。我們不知道系統將首先選擇哪個線程作為可調度線程。當該線程完成操作時,它也將調用S e t E v e n t函數,使下一個被調度。這樣,三個線程會以先後順序執行,至於什麼順序,那是作業系統決定的。所以,就算每個輔助線程均以讀/寫方式訪問記憶體塊,也不會產生任何問題,這些線程將不再被要求將資料視為唯讀資料。

 

  這個例子清楚地展示出使用人工重設事件與自動重設事件之間的差別。

 

  P u l s e E v e n t函數使得事件變為已通知狀態,然後立即又變為未通知狀態,這就像在調用S e t E v e n t後又立即調用R e s e t E v e n t函數一樣。如果在人工重設的事件上調用P u l s e E v e n t函數,那麼在發出該事件時,等待該事件的任何一個線程或所有線程將變為可調度線程。如果在自動重設事件上調用P u l s e E v e n t函數,那麼只有一個等待該事件的線程變為可調度線程。如果在發出事件時沒有任何線程在等待該事件,那麼將不起任何作用[2]。

 

  2、 Critical Section

 

  使用臨界地區的第一個忠告就是不要長時間鎖住一份資源。這裡的長時間是相對的,視不同程式而定。對一些控制軟體來說,可能是數毫秒,但是對另外一些程式來說,可以長達數分鐘。但進入臨界區後必須儘快地離開,釋放資源。如果不釋放的話,會如何?答案是不會怎樣。如果是主線程(GUI線程)要進入一個沒有被釋放的臨界區,呵呵,程式就會掛了!臨界地區的一個缺點就是:Critical Section不是一個核心對象,無法獲知進入臨界區的線程是生是死,如果進入臨界區的線程掛了,沒有釋放臨界資源,系統無法獲知,而且沒有辦法釋放該臨界資源。這個缺點在互斥器(Mutex)中得到了彌補。Critical Section在MFC中的相應實作類別是CcriticalSection。CcriticalSection::Lock()進入臨界區,CcriticalSection::UnLock()離開臨界區。

 

  3、 Mutex

 

  互斥器的功能和臨界地區很相似。區別是:Mutex所花費的時間比Critical Section多的多,但是Mutex是核心對象(Event、Semaphore也是),可以跨進程使用,而且等待一個被鎖住的Mutex可以設定TIMEOUT,不會像Critical Section那樣無法得知臨界地區的情況,而一直死等。MFC中的對應類為CMutex。Win32函數有:建立互斥體CreateMutex() ,開啟互斥體OpenMutex(),釋放互斥體ReleaseMutex()。Mutex的擁有權並非屬於那個產生它的線程,而是最後那個對此Mutex進行等待操作(WaitForSingleObject等等)並且尚未進行ReleaseMutex()操作的線程。線程擁有Mutex就好像進入Critical Section一樣,一次只能有一個線程擁有該Mutex。如果一個擁有Mutex的線程在返回之前沒有調用ReleaseMutex(),那麼這個Mutex就被捨棄了,但是當其他線程等待(WaitForSingleObject等)這個Mutex時,仍能返回,並得到一個WAIT_ABANDONED_0傳回值。能夠知道一個Mutex被捨棄是Mutex特有的。

 

  4、 Semaphore

 

  訊號量是最具曆史的同步機制。訊號量是解決producer/consumer問題的關鍵要素。對應的MFC類是Csemaphore。Win32函數CreateSemaphore()用來產生訊號量。ReleaseSemaphore()用來解除鎖定。Semaphore的現值代表的意義是目前可用的資源數,如果Semaphore的現值為1,表示還有一個鎖定動作可以成功。如果現值為5,就表示還有五個鎖定動作可以成功。當調用Wait…等函數要求鎖定,如果Semaphore現值不為0,Wait…馬上返回,資源數減1。當調用ReleaseSemaphore()資源數加1,當然不會超過初始設定的資源總數。

 編輯本段有關多線程的一些技術問題

  1、 何時使用多線程?

 

  2、 線程如何同步?

 

  3、 線程之間如何通訊?

 

  4、 進程之間如何通訊?

 

  先來回答第一個問題,線程實際主要應用於四個主要領域,當然各個領域之間不是絕對孤立的,他們有可能是重疊的,但是每個程式應該都可以歸於某個領域:

 

  1、 offloading time-consuming task。由輔助線程來執行耗時計算,而使GUI有更好的反應。我想這應該是我們考慮使用線程最多的一種情況吧。

 

  2、 Scalability。伺服器軟體最常考慮的問題,在程式中產生多個線程,每個線程做一份小的工作,使每個CPU都忙碌,使CPU(一般是多個)有最佳的使用率,達到負載的均衡,這比較複雜,我想以後再討論這個問題。

 

  3、 Fair-share resource allocation。當你向一個負荷沉重的伺服器發出請求,多少時間才能獲得服務。一個伺服器不能同時為太多的請求服務,必須有一個請求的最大個數,而且有時候對某些請求要優先處理,這是線程優先順序乾的活了。

 

  4、 Simulations。線程用於模擬測試。

 編輯本段線程之間的通訊

  線程常常要將資料傳遞給另外一個線程。Worker線程可能需要告訴別人說它的工作完成了,GUI線程則可能需要交給Worker線程一件新的工作。

 

  通過PostThreadMessage(),可以將訊息傳遞給目標線程,當然目標線程必須有訊息佇列。以訊息當作通訊方式,比起標準技術如使用全域變數等,有很大的好處。如果對象是同一進程中的線程,可以發送自訂訊息,傳遞資料給目標線程,如果是線程在不同的進程中,就涉及進程之間的通訊了。下面將會講到。

 

  進程之間的通訊:

 

  當線程分屬於不同進程,也就是分駐在不同的地址空間時,它們之間的通訊需要跨越地址空間的邊界,便得採取一些與同一進程中不同線程間通訊不同的方法。

 

  1、 Windows專門定義了一個訊息:WM_COPYDATA,用來線上程之間搬移資料,――不管兩個線程是否同屬於一個進程。同時接受這個訊息的線程必須有一個視窗,即必須是UI線程。WM_COPYDATA必須由SendMessage()來發送,不能由PostMessage()等來發送,這是由待發送資料緩衝區的生命期決定的,出於安全的需要。

 

  2、 WM_COPYDATA效率上面不是太高,如果要求高效率,可以考慮使用共用記憶體(Shared Memory)。使用共用記憶體要做的是:設定一塊記憶體共用地區;使用共用記憶體;同步處理共用記憶體。

 

  第一步:設定一塊記憶體共用地區。首先,CreateFileMapping()產生一個file-mapping核心對象,並指定共用地區的大小。MapViewOfFile()獲得一個指標指向可用的記憶體。如果是C/S模式,由Server端來產生file-mapping,那麼Client端使用OpenFileMapping(),然後調用MapViewOfFile()。

 

  第二步:使用共用記憶體。共用記憶體指標的使用是一件比較麻煩的事,我們需要藉助_based屬性,允許指標被定義為從某一點開始起算的32位位移值。

 

  第三步:清理。UnmapViewOfFile()交出由MapViewOfFile()獲得的指標,CloseHandle()交出file-mapping核心對象的handle。

 

  第四步:同步處理。可以藉助Mutex來進行同步處理。

 

  3、 IPC

 

  1)Anonymous Pipes。Anonymous Pipes只被使用於點對點通訊。當一個進程產生另一個進程時,這是最有用的一種通訊方式。

 

  2)Named Pipes。Named Pipes可以是單向,也可以是雙向,並且可以跨越網路,步局限於單機。

 

  3)Mailslots。Mailslots為廣播式通訊。Server進程可以產生Mailslots,任何Client進程可以寫資料進去,但是只有Server進程可以取資料。

 

  4)OLE Automation。OLE Automation和UDP都是更高階的機制,允許通訊發生於不同進程間,甚至不同機器間。

 

  5)DDE。DDE動態資料交換,使用於16位Windows,目前這一方式應盡量避免使用。[3]

內容來自網路資源:http://baike.baidu.com/view/2808915.htm

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.