線程同步機制的區別與比較及進程通訊方法

有關多線程的一些技術問題:安全

一、  什麼時候使用多線程?服務器

二、  線程如何同步?網絡

三、  線程之間如何通信?多線程

四、  進程之間如何通信?app

 

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

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

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

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

四、  Simulations。線程用於仿真測試。線程

我把主要的目光放在第一個領域,由於它正是我想要的。第二和第三個領域比較有意思,可是目前不在個人研究時間表中。

 

線程的同步機制:

一、  Event
用事件(Event)來同步線程是最具彈性的了。一個事件有兩種狀態:激發狀態和未激發狀態。也稱有信號狀態和無信號狀態。事件又分兩種類型:手動重置事件和自動重置事件。手動重置事件被設置爲激發狀態後,會喚醒全部等待的線程,並且一直保持爲激發狀態,直到程序從新把它設置爲未激發狀態。自動重置事件被設置爲激發狀態後,會喚醒「一個」等待中的線程,而後自動恢復爲未激發狀態。因此用自動重置事件來同步兩個線程比較理想。MFC中對應的類爲CEvent.。CEvent的構造函數默認建立一個自動重置的事件,並且處於未激發狀態。共有三個函數來改變事件的狀態:SetEvent,ResetEvent和PulseEvent。用事件來同步線程是一種比較理想的作法,但在實際的使用過程當中要注意的是,對自動重置事件調用SetEvent和PulseEvent有可能會引發死鎖,必須當心。

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

三、  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特有的。

四、  Semaphore
信號量是最具歷史的同步機制。信號量是解決producer/consumer問題的關鍵要素。對應的MFC類是Csemaphore。Win32函數CreateSemaphore()用來產生信號量。ReleaseSemaphore()用來解除鎖定。Semaphore的現值表明的意義是目前可用的資源數,若是Semaphore的現值爲1,表示還有一個鎖定動做能夠成功。若是現值爲5,就表示還有五個鎖定動做能夠成功。當調用Wait…等函數要求鎖定,若是Semaphore現值不爲0,Wait…立刻返回,資源數減1。當調用ReleaseSemaphore()資源數加1,當時不會超過初始設定的資源總數。

 

線程之間的通信:
線程經常要將數據傳遞給另一個線程。Worker線程可能須要告訴別人說它的工做完成了,GUI線程則可能須要交給Worker線程一件新的工做。
經過PostThreadMessage(),能夠將消息傳遞給目標線程,固然目標線程必須有消息隊列。以消息看成通信方式,比起標準技術如使用全局變量等,有很大的好處。若是對象是同一進程中的線程,能夠發送自定義消息,傳遞數據給目標線程,若是是線程在不一樣的進程中,就涉及進程之間的通信了。下面將會講到。

 

進程之間的通信:

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

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

二、  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來進行同步處理。

三、  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,目前這一方式應儘可能避免使用。 

本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/eulb/archive/2008/03/13/2177500.aspx

 

 

________________________________________________

多線程同步機制 (Windows)

 

線程的同步機制:

一、   Event
用事件(Event)來同步線程是最具彈性的了。一個事件有兩種狀態:激發狀態和未激發狀態。也稱有信號狀態和無信號狀態。事件又分兩種類型:手動重置事件和自動重置事件。手動重置事件被設置爲激發狀態後,會喚醒全部等待的線程,並且一直保持爲激發狀態,直到程序從新把它設置爲未激發狀態。自動重置事件被設置爲激發狀態後,會喚醒「一個」等待中的線程,而後自動恢復爲未激發狀態。因此用自動重置事件來同步兩個線程比較理想。MFC中對應的類爲 CEvent.。CEvent的構造函數默認建立一個自動重置的事件,並且處於未激發狀態。共有三個函數來改變事件的狀態:SetEvent,ResetEvent和PulseEvent。用事件來同步線程是一種比較理想的作法,但在實際的使用過程當中要注意的是,對自動重置事件調用SetEvent和PulseEvent有可能會引發死鎖,必須當心。

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

三、   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特有的。

四、   Semaphore
信號量是最具歷史的同步機制。信號量是解決producer/consumer問題的關鍵要素。對應的MFC類是Csemaphore。Win32函數 CreateSemaphore()用來產生信號量。ReleaseSemaphore()用來解除鎖定。Semaphore的現值表明的意義是目前可用的資源數,若是Semaphore的現值爲1,表示還有一個鎖定動做能夠成功。若是現值爲5,就表示還有五個鎖定動做能夠成功。當調用Wait…等函數要求鎖定,若是Semaphore現值不爲0,Wait…立刻返回,資源數減1。當調用ReleaseSemaphore()資源數加1,當時不會超過初始設定的資源總數。

線程之間的通信:
線程經常要將數據傳遞給另一個線程。Worker線程可能須要告訴別人說它的工做完成了,GUI線程則可能須要交給Worker線程一件新的工做。經過PostThreadMessage(),能夠將消息傳遞給目標線程,固然目標線程必須有消息隊列。以消息看成通信方式,比起標準技術如使用全局變量等,有很大的好處。若是對象是同一進程中的線程,能夠發送自定義消息,傳遞數據給目標線程,若是是線程在不一樣的進程中,就涉及進程之間的通信了。下面將會講到。進程之間的通信:當線程分屬於不一樣進程,也就是分駐在不一樣的地址空間時,它們之間的通信須要跨越地址空間的邊界,便得采起一些與同一進程中不一樣線程間通信不一樣的方法。一、   Windows專門定義了一個消息:WM_COPYDATA,用來在線程之間搬移數據,――無論兩個線程是否同屬於一個進程。同時接受這個消息的線程必須有一個窗口,即必須是UI線程。WM_COPYDATA必須由SendMessage()來發送,不能由PostMessage()等來發送,這是由待發送數據緩衝區的生命期決定的,出於安全的須要。二、   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來進行同步處理。三、   IPC1)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,目前這一方式應儘可能避免使用。

相關文章
相關標籤/搜索