多線程編程精髓(二)

基于上篇的多線程編程的基本內(nèi)容,本篇開(kāi)始Windows操作系統(tǒng)下各種常用的多線程資源同步對(duì)象婿失。

(1)windows線程資源同步之臨界區(qū):兩個(gè)重要的 Windows API 函數(shù) WaitForSingleObject 和 WaitForMultipleObjects辟躏,前者是一次操作一個(gè)資源同步對(duì)象辆憔,后者同時(shí)操作多個(gè)資源

同步對(duì)象渣蜗,區(qū)別和注意點(diǎn)如下:

? ? ? ? ? ? ?? 1.DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds); //參數(shù)hhandle表示需要等待的內(nèi)核對(duì)象,參數(shù)dwMilliseconds 實(shí)際上是一個(gè)?unsigned long 類

型县遣,設(shè)置 INFINITE 表示無(wú)限等待糜颠,在 Windows 上可以調(diào)用WaitForSingleObject等待的常見(jiàn)對(duì)象如下表所示:

? ? ? ? ? ? ? ? ? ? ?? 可以被等待的對(duì)象 ? ? ? ? ? ? ? ?? 等待對(duì)象成功的含義 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 對(duì)象類型

? ? ? ? ? ? ? ? ? ? ? ? 線程 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 等待線程結(jié)束 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? HANDLE

? ? ? ? ? ? ? ? ? ? ?? Process ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 等待進(jìn)程結(jié)束 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? HANDLE

? ? ? ? ? ? ? ? ? ? ?? Event(事件) ? ? ? ? ? ? ? ? ? ? ?? 等待 Event 有信號(hào) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? HANDLE

? ? ? ? ? ? ? ? ? ? ?? Mutex (互斥體) ? ? ? ? ? ? ? ? ? ? ? 等待持有 Mutex 的線程釋放該 Mutex汹族,等待成功,擁有該 Mutex ? ? HANDLE

? ? ? ? ? ? ? ? ? ? ?? Semaphore(信號(hào)量) ? ? ? ?? 等待該 Semaphore 對(duì)象有信號(hào) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? HANDLE

? ? ? ? ? ?? 函數(shù)的返回類型有:WAIT_FAILED -調(diào)用失敗其兴,可以用GetLastError()得到具體的錯(cuò)誤碼顶瞒,WAIT_OBJECT_0-表示成功等待到設(shè)置的對(duì)象,WAIT_TIMEOUT-等待超時(shí)

WAIT_ABANDONED-當(dāng)?shù)却膶?duì)象是 Mutex 類型時(shí)元旬,如果持有該 Mutex 對(duì)象的線程已經(jīng)結(jié)束榴徐,但是沒(méi)有在結(jié)束前釋放該 Mutex,此時(shí)該 Mutex 已經(jīng)處于廢棄狀態(tài)匀归,其行為是未知的坑资,

不建議再使用。

? ? ? ? ? ? 2. DWORD WaitForMultipleObjects( DWORD nCount,const HANDLE *lpHandles, BOOL bWaitAll, DWORD dwMilliseconds);? //nCount 指定對(duì)象數(shù)組的長(zhǎng)度穆端,lpHandles表示需要

等待的對(duì)象數(shù)組指針袱贮,bWaitAll表示是否等待所有對(duì)象數(shù)組有信號(hào),可設(shè)置true或者false体啰,設(shè)置false只要有一個(gè)對(duì)象有信號(hào)即會(huì)返回攒巍,在設(shè)置bWaitAll 為false的情況下, 除了和上述介紹

的返回值是 WAITFAILED和荒勇,柒莉,WAITTIMEOUT 以外,由于是多個(gè)對(duì)象同步沽翔,返回值 WAIT_OBJECT_0 to (WAIT_OBJECT_0 + nCount– 1)兢孝,比如:現(xiàn)在等待三個(gè)對(duì)象 A1、A2搀擂、A3西潘,

它們?cè)跀?shù)組 lpHandles 中的下標(biāo)依次是 0、1哨颂、2,某次 WaitForMultipleObjects 返回值是 Wait_OBJECT_0 + 1相种,則表示對(duì)象 A2 有信號(hào)威恼,導(dǎo)致 WaitForMultipleObjects 調(diào)用成功返回。同

理對(duì)于WAIT_ABANDONED_0 to (WAIT_ABANDONED_0 + nCount– 1)寝并。

? ? ? ? ?? windows的臨界區(qū)對(duì)象操作API函數(shù):

? ? ? ? ? void ?? InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection);? //初始化臨界區(qū)對(duì)象

? ? ? ? ? void ?? DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection);? //銷毀臨界區(qū)對(duì)象

? ? ? ? ? BOOL TryEnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection); //嘗試進(jìn)入臨界區(qū)箫措,如果是,返回true衬潦,無(wú)法進(jìn)入則阻塞斤蔓,返回false

? ? ? ? ? void ? ? EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);? //進(jìn)入臨界區(qū)

? ? ? ? ? void ? ? LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection); //離開(kāi)臨界區(qū)

? ? ? ?? 注意:此臨界區(qū)對(duì)象是互斥的箭跳,只能一個(gè)線程訪問(wèn)持有漂彤,為了避免死鎖慨削,進(jìn)入和離開(kāi)臨界區(qū)函數(shù)需要成對(duì)使用旨涝,為了避免因函數(shù)有多個(gè)出口造成的編碼疏漏,可使用 RAII 封裝臨界

區(qū)對(duì)象類的方法驾锰,此API函數(shù)為Windows 系統(tǒng)多線程資源同步最常用的對(duì)象之一卸留。

(2)windows線程資源同步之Event:Event是windows內(nèi)核的常用多線程同步的對(duì)象,特點(diǎn)是簡(jiǎn)單易用椭豫,但無(wú)法精確控制喚醒指定數(shù)量的線程耻瑟。API函數(shù) 為:

? ? ? ?? HANDLE CreateEvent( LPSECURITY_ATTRIBUTES lpEventAttributes,BOOL ? bManualReset, BOOL? bInitialState,LPCTSTR ? lpName); ?? //參數(shù)lpEventAttributes 設(shè)置Event對(duì)象

的安全屬性,設(shè)置NULL為默認(rèn)安全屬性赏酥;參數(shù)bManualReset表示設(shè)置 Event 對(duì)象受信(變成有信號(hào)狀態(tài))時(shí)的行為喳整,設(shè)置true要手動(dòng)調(diào)用 ResetEvent 函數(shù)去將 Event 重置成無(wú)信號(hào)

狀態(tài),設(shè)置false表示Event 事件對(duì)象受信后會(huì)自動(dòng)重置為無(wú)信號(hào)狀態(tài)裸扶;參數(shù) bInitialState 設(shè)置 Event 事件對(duì)象初始狀態(tài)是否是受信的算柳,true表示有信號(hào),false表示無(wú)信號(hào)姓言;參數(shù) lpName?

可以設(shè)置 Event 對(duì)象的名稱瞬项,可設(shè)置為NULL,Event對(duì)象可以通過(guò)名稱在進(jìn)程之前不同進(jìn)程之間共享何荚;返回值為 NULL表示創(chuàng)建失敗囱淋。

? ? ? ? ? ? BOOL? SetEvent(HANDLE hEvent); //設(shè)置Event對(duì)象從無(wú)信號(hào)變成有信號(hào)狀態(tài)

? ? ? ? ? ? BOOL? ResetEvent(HANDLE hEvent); //設(shè)置Event對(duì)象從有信號(hào)變成無(wú)信號(hào)狀態(tài)

(3)windows線程同步之Mutex:windows的Mutex(互斥量)在同一時(shí)刻只能屬于一個(gè)線程,也可以不屬于任何線程餐塘,具有排他性妥衣,創(chuàng)建Mutex可設(shè)置它屬于的線程,其他線程要獲取調(diào)

用WaitForSingleObject 進(jìn)行申請(qǐng)戒傻,創(chuàng)建 Mutex 的 API 是 CreateMutex税手,釋放 Mutex 的 API 是ReleaseMutex :

? ? ? ? ?? HANDLE CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL? bInitialOwner, LPCTSTR? lpName);? //參數(shù) lpMutexAttributes 與Event函數(shù)類似,設(shè)置?

lpMutexAttribute為NULL需纳,參數(shù) bInitialOwner表示調(diào)用創(chuàng)建Mutex的線程是否立即擁有該對(duì)象芦倒,true為擁有,fasle為不擁有不翩;參數(shù) lpName為Mutex 對(duì)象的名稱兵扬,和Event對(duì)象一樣,多個(gè)

線程之間可通過(guò)名稱共享口蝠;返回值為NULL表示創(chuàng)建失斊髦印;

? ? ? ? ?? BOOL ReleaseMutex(HANDLE hMutex); //? 參數(shù) hMutex 即需要釋放所有權(quán)的 Mutex 對(duì)象句柄

(4)windows線程同步之Semaphore:Semaphore 也是 Windows 多線程同步常用的對(duì)象之一妙蔗,與Event傲霸、Mutex區(qū)別不同的是可以信號(hào)量存在資源計(jì)數(shù),可以精確控制喚醒的線程數(shù)

目。創(chuàng)建 Semaphore 對(duì)象的 API 函數(shù)和增加信號(hào)量資源個(gè)數(shù)的API如下所示:

? ? ? ? ? HANDLE? CreateSemaphore(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,LONG? lInitialCount, LONG lMaximumCount,LPCTSTR ? lpName);? //參數(shù)?

lpSemaphoreAttributes 指定對(duì)象的安全屬性昙啄,設(shè)置為NULL;參數(shù) lInitialCount 指定初始可用資源數(shù)量,每調(diào)用一次 WaitForSingleObject 獲得 Semaphore 對(duì)象穆役,該對(duì)象的資源計(jì)數(shù)會(huì)

減少一個(gè),參數(shù) lMaximumCount 最大資源數(shù)量上限跟衅,設(shè)置大于0孵睬,使用ReleaseSemaphore 增加資源個(gè)數(shù)不能大于這個(gè)上限值;參數(shù) lpName 指定 Semaphore 對(duì)象的名稱伶跷,可通過(guò)

名稱進(jìn)行跨進(jìn)程共享掰读;返回值為NULL表示創(chuàng)建失敗。

? ? ? ? ? BOOL? ReleaseSemaphore( HANDLE hSemaphore,LONG? lReleaseCount,? LPLONG lpPreviousCount);? //新增信號(hào)量的資源個(gè)數(shù)個(gè)數(shù)叭莫,參數(shù) hSemaphore 是需要操作的信號(hào)量

句柄蹈集;參數(shù) lReleaseCount,需要增加的資源數(shù)量雇初;參數(shù) lpPreviousCount 是一個(gè) long 型(32 位系統(tǒng)上 4 個(gè)字節(jié))的指針拢肆,返回上一次資源的數(shù)量。

? ? ? ? 信號(hào)量根據(jù)當(dāng)前資源的個(gè)數(shù)分配消費(fèi)者靖诗,當(dāng)資源數(shù)量為0時(shí)郭怪,所有消費(fèi)者處于掛起狀態(tài),當(dāng)新資源到來(lái)時(shí)刊橘,消費(fèi)者會(huì)被喚醒鄙才。

(5)讓程序只啟動(dòng)一個(gè)實(shí)例的方法:使用線程內(nèi)核同步對(duì)象,首次啟動(dòng)這個(gè)進(jìn)程促绵,這個(gè)進(jìn)程會(huì)調(diào)用 CreateMutex 函數(shù)創(chuàng)建一個(gè)名稱為“MySingleInstanceApp”的互斥體對(duì)象攒庵。當(dāng)再次準(zhǔn)備

啟動(dòng)一份這個(gè)進(jìn)程時(shí),再次調(diào)用 CreateMutex 函數(shù)败晴,由于該名稱的互斥體對(duì)象已經(jīng)存在浓冒,將會(huì)返回已經(jīng)存在的互斥體對(duì)象地址,此時(shí)通過(guò) GetLastError() 函數(shù)得到的錯(cuò)誤碼是?

ERROR_ALREADY_EXISTS 表示該名稱的互斥體對(duì)象已經(jīng)存在尖坤,此時(shí)我們激活已經(jīng)存在的前一個(gè)實(shí)例稳懒,然后退出當(dāng)前進(jìn)程即可。如下函數(shù)實(shí)現(xiàn):

? ? ? ? ? bool CheckInstance()

? ? ? ? {

? ? ? ? ? ? ?? HANDLE hSingleInstanceMutex = CreateMutex(NULL, FALSE, _T("MySingleInstanceApp"));

? ? ? ? ? ? ? if (hSingleInstanceMutex != NULL)

? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? if (GetLastError() == ERROR_ALREADY_EXISTS)

? ? ? ? ? ? ? ? ?? {

? ? ? ? ? ? ? ? ? ? ? ? ? return true;

? ? ? ? ? ? ? ? ? }

? ? ? ? ?? }

? ? ? ? ?? return false;

? ?? }?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末糖驴,一起剝皮案震驚了整個(gè)濱河市僚祷,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌贮缕,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,525評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件俺榆,死亡現(xiàn)場(chǎng)離奇詭異感昼,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)罐脊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門定嗓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)蜕琴,“玉大人,你說(shuō)我怎么就攤上這事宵溅×杓颍” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 164,862評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵恃逻,是天一觀的道長(zhǎng)雏搂。 經(jīng)常有香客問(wèn)我,道長(zhǎng)寇损,這世上最難降的妖魔是什么凸郑? 我笑而不...
    開(kāi)封第一講書人閱讀 58,728評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮矛市,結(jié)果婚禮上芙沥,老公的妹妹穿的比我還像新娘。我一直安慰自己浊吏,他們只是感情好而昨,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著找田,像睡著了一般歌憨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上午阵,一...
    開(kāi)封第一講書人閱讀 51,590評(píng)論 1 305
  • 那天躺孝,我揣著相機(jī)與錄音,去河邊找鬼底桂。 笑死植袍,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的籽懦。 我是一名探鬼主播于个,決...
    沈念sama閱讀 40,330評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼暮顺!你這毒婦竟也來(lái)了厅篓?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,244評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤捶码,失蹤者是張志新(化名)和其女友劉穎羽氮,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體惫恼,經(jīng)...
    沈念sama閱讀 45,693評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡档押,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片令宿。...
    茶點(diǎn)故事閱讀 40,001評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡叼耙,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出粒没,到底是詐尸還是另有隱情筛婉,我是刑警寧澤,帶...
    沈念sama閱讀 35,723評(píng)論 5 346
  • 正文 年R本政府宣布癞松,位于F島的核電站爽撒,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏拦惋。R本人自食惡果不足惜匆浙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望厕妖。 院中可真熱鬧首尼,春花似錦、人聲如沸言秸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,919評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)举畸。三九已至查排,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間抄沮,已是汗流浹背跋核。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,042評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留叛买,地道東北人砂代。 一個(gè)月前我還...
    沈念sama閱讀 48,191評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像率挣,于是被迫代替她去往敵國(guó)和親刻伊。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 一椒功、上路吧捶箱,線程 從Win32角度看,進(jìn)程含有內(nèi)存(理論上可達(dá)2G)和資源动漾,本身并不能夠執(zhí)行丁屎,只是提供一個(gè)安置內(nèi)存...
    赤果_b4a7閱讀 780評(píng)論 0 1
  • LINUX 基礎(chǔ)知識(shí) 1、線程的概念 上下文切換 : 運(yùn)行程序前需要將相應(yīng)進(jìn)程信息讀入內(nèi)存旱眯,如果運(yùn)行進(jìn)程A后需要緊...
    Ycres閱讀 764評(píng)論 0 2
  • 引用自多線程編程指南應(yīng)用程序里面多個(gè)線程的存在引發(fā)了多個(gè)執(zhí)行線程安全訪問(wèn)資源的潛在問(wèn)題悦屏。兩個(gè)線程同時(shí)修改同一資源有...
    Mitchell閱讀 1,990評(píng)論 1 7
  • 本文根據(jù)眾多互聯(lián)網(wǎng)博客內(nèi)容整理后形成节沦,引用內(nèi)容的版權(quán)歸原始作者所有键思,僅限于學(xué)習(xí)研究使用础爬,不得用于任何商業(yè)用途。 互...
    深紅的眼眸閱讀 1,100評(píng)論 0 0
  • 1.內(nèi)存的頁(yè)面置換算法 (1)最佳置換算法(OPT)(理想置換算法):從主存中移出永遠(yuǎn)不再需要的頁(yè)面供炎;如無(wú)這樣的...
    杰倫哎呦哎呦閱讀 3,249評(píng)論 1 9