日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

c++多線程同步使用的對象

 禁忌石 2017-05-05

c++多線程同步使用的對象

線程的同步

Critical section(臨界區(qū))用來實現(xiàn)“排他性占有”。適用范圍是單一進程的各線程之間。它是:

·         一個局部性對象,不是一個核心對象。

·         快速而有效率

·         不能夠同時有一個以上的critical section被等待。

·         無法偵測是否已被某個線程放棄

Mutex

Mutex是一個核心對象,可以在不同的線程之間實現(xiàn)“排他性占有”,甚至幾十那些現(xiàn)成分屬不同進程。它是:

·         一個核心對象。

·         如果擁有mutex的那個線程結(jié)束,則會產(chǎn)生一個“abandoned”錯誤信息。

·         可以使用Wait…()等待一個mutex。

·         可以具名,因此可以被其他進程開啟。

·         只能被擁有它的那個線程釋放(released)。

Semaphore

Semaphore被用來追蹤有限的資源。它是:

·         一個核心對象。

·         沒有擁有者。

·         可以具名,因此可以被其他進程開啟。

·         可以被任何一個線程釋放(released)。

Event Object

Event object通常使用于overlapped I/O,或用來設(shè)計某些自定義的同步對象。它是:

·         一個核心對象。

·         完全在程序掌控之下。

·         適用于設(shè)計新的同步對象。

·         “要求蘇醒”的請求并不會被儲存起來,可能會遺失掉。

·         可以具名,因此可以被其他進程開啟

Interlocked Variable

如果Interlocked…()函數(shù)被使用于所謂的spin-lock,那么他們只是一種同步機制。所謂spin-lock是一種busy loop,被預期在極短時間內(nèi)執(zhí)行,所以有最小的額外負擔(overhead)。系統(tǒng)核心偶爾會使用他們。除此之外,interlocked variables主要用于引用技術(shù)。他們:

·         允許對4字節(jié)的數(shù)值有些基本的同步操作,不需動用到critical section或mutex之類。

·         在SMP(Symmetric Multi-Processors)操作系統(tǒng)中亦可有效運作。

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

有關(guān)多線程的一些技術(shù)問題:

1、   何時使用多線程?

2、   線程如何同步?

3、   線程之間如何通訊?

4、   進程之間如何通訊?

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

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

2、   Scalability。服務器軟件最??紤]的問題,在程序中產(chǎn)生多個線程,每個線程做一份小的工作,使每個CPU都忙碌,使CPU(一般是多個)有最佳的使用率,達到負載的均衡,這比較復雜,我想以后再討論這個問題。

3、   Fair-share resource allocation。當你向一個負荷沉重的服務器發(fā)出請求,多少時間才能獲得服務。一個服務器不能同時為太多的請求服務,必須有一個請求的最大個數(shù),而且有時候?qū)δ承┱埱笠獌?yōu)先處理,這是線程優(yōu)先級干的活了。

4、   Simulations。線程用于仿真測試。

我把主要的目光放在第一個領(lǐng)域,因為它正是我想要的。第二和第三個領(lǐng)域比較有意思,但是目前不在我的研究時間表中。

線程的同步機制:

1、   Event

用事件(Event)來同步線程是最具彈性的了。一個事件有兩種狀態(tài):激發(fā)狀態(tài)和未激發(fā)狀態(tài)。也稱有信號狀態(tài)和無信號狀態(tài)。事件又分兩種類型:手動重置事件和自動重置事件。手動重置事件被設(shè)置為激發(fā)狀態(tài)后,會喚醒所有等待的線程,而且一直保持為激發(fā)狀態(tài),直到程序重新把它設(shè)置為未激發(fā)狀態(tài)。自動重置事件被設(shè)置為激發(fā)狀態(tài)后,會喚醒“一個”等待中的線程,然后自動恢復為未激發(fā)狀態(tài)。所以用自動重置事件來同步兩個線程比較理想。MFC中對應的類為CEvent.。CEvent的構(gòu)造函數(shù)默認創(chuàng)建一個自動重置的事件,而且處于未激發(fā)狀態(tài)。共有三個函數(shù)來改變事件的狀態(tài):SetEvent,ResetEvent和PulseEvent。用事件來同步線程是一種比較理想的做法,但在實際的使用過程中要注意的是,對自動重置事件調(diào)用SetEvent和PulseEvent有可能會引起死鎖,必須小心。

2、   Critical Section

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

3、   Mutex

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

4、   Semaphore

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

線程之間的通訊:

線程常常要將數(shù)據(jù)傳遞給另外一個線程。Worker線程可能需要告訴別人說它的工作完成了,GUI線程則可能需要交給Worker線程一件新的工作。

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

進程之間的通訊:

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

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

2、   WM_COPYDATA效率上面不是太高,如果要求高效率,可以考慮使用共享內(nèi)存(Shared Memory)。使用共享內(nèi)存要做的是:設(shè)定一塊內(nèi)存共享區(qū)域;使用共享內(nèi)存;同步處理共享內(nèi)存。

第一步:設(shè)定一塊內(nèi)存共享區(qū)域。首先,CreateFileMapping()產(chǎn)生一個file-mapping核心對象,并指定共享區(qū)域的大小。MapViewOfFile()獲得一個指針指向可用的內(nèi)存。如果是C/S模式,由Server端來產(chǎn)生file-mapping,那么Client端使用OpenFileMapping(),然后調(diào)用MapViewOfFile()。

第二步:使用共享內(nèi)存。共享內(nèi)存指針的使用是一件比較麻煩的事,我們需要借助_based屬性,允許指針被定義為從某一點開始起算的32位偏移值。

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

第四步:同步處理??梢越柚鶰utex來進行同步處理。

  雖然多線程能給我們帶來好處,但是也有不少問題需要解決。例如,對于像磁盤驅(qū)動器這樣獨占性系統(tǒng)資源,由于線程可以執(zhí)行進程的任何代碼段,且線程的運行是由系統(tǒng)調(diào)度自動完成的,具有一定的不確定性,因此就有可能出現(xiàn)兩個線程同時對磁盤驅(qū)動器進行操作,從而出現(xiàn)操作錯誤;又例如,對于銀行系統(tǒng)的計算機來說,可能使用一個線程來更新其用戶數(shù)據(jù)庫,而用另外一個線程來讀取數(shù)據(jù)庫以響應儲戶的需要,極有可能讀數(shù)據(jù)庫的線程讀取的是未完全更新的數(shù)據(jù)庫,因為可能在讀的時候只有一部分數(shù)據(jù)被更新過。

  使隸屬于同一進程的各線程協(xié)調(diào)一致地工作稱為線程的同步。MFC提供了多種同步對象,下面我們只介紹最常用的四種:

  • 臨界區(qū)(CCriticalSection)
  • 事件(CEvent)
  • 互斥量(CMutex)
  • 信號量(CSemaphore)
     

通過這些類,我們可以比較容易地做到線程同步。

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多