C++關(guān)于臨界區(qū)CCriticalSection的線程同步 網(wǎng)狐框架示例

今天早上在gitbook上翻譯了msdn文檔里的Critical Section Objects,渣渣翻譯。

1. 臨界區(qū)

1.1臨界區(qū)是什么

臨界區(qū)與互斥量、事件、信號一樣,都提供了一種同步機制。臨界區(qū)在同一時間內(nèi)僅能被一個線程所擁有,這對于保護共享資源不被并發(fā)訪問非常有用。但是它只能在單進程中使用,無法跨進程共享。

1.1.1什么是同步,什么是異步?

同步和異步關(guān)注的是消息通信機制
以下的理解來自于知乎(愚抄 嚴肅 陳碩
下面用兩個例子來解釋同步和異步:

  • 當(dāng)你用水壺?zé)粔厮?,此時有兩種水壺,一種是燒開不會響笛的水壺A,另一種是燒開會響笛的水壺B。
    當(dāng)你使用水壺A燒水的時候,你需要自己來看看水有沒有燒開,這就是同步
    當(dāng)你使用水壺B燒水的時候,水燒開了它自動就會通知你,這就是異步

  • 你打電話給書店老板,問有沒有《C++ primer》這本書。
    同步機制里,老板會說“稍等,我找找”,然后就開始查找,等查好了就告訴你結(jié)果(返回結(jié)果)。
    異步機制里,老板會說“我去找一下,查到了再打電話給你”,然后直接掛掉電話(不返回結(jié)果),查好了他就主動打電話給你(相當(dāng)于回調(diào)函數(shù))。

需要注意的一個重點:在處理IO的時候,阻塞與非阻塞都是同步IO

同步與異步

1.2 如何使用臨界區(qū)

當(dāng)該臨界區(qū)對象被某個線程占用時,另一個線程想要訪問該對象,線程就會進入休眠狀態(tài),直到臨界區(qū)對象被釋放,才會喚醒該線程。

因為喚醒線程需要時間,所以現(xiàn)在為了避免性能降低。在另一個線程訪問對象且該對象已被占用的時候,設(shè)置一個循環(huán)訪問次數(shù),在這個次數(shù)內(nèi)不斷循環(huán)訪問臨界區(qū)對象,如果該對象被釋放,這個線程就不會進入休眠。如果該對象在循環(huán)次數(shù)內(nèi)依舊沒有釋放,線程就會進入線程。

2. CCriticalSection(臨界區(qū))同步對象

2.1 關(guān)于CCriticalSection

CCriticalSection是MFC提供的一種同步對象。它是一個用于同步的對象,同一時刻只允許一個線程存取資源或代碼區(qū)。

2.2 CCriticalSection的用法
  1. 定義一個CCriticalSection類的全局對象,因為是全局對象,那么各個線程均可以訪問。
  2. 在訪問需要保護的資源或代碼之前,調(diào)用CCriticalSection類的成員Lock()獲得臨界區(qū)對象。
    在線程中調(diào)用該函數(shù)來使線程獲得它所請求的臨界區(qū),如果此時沒有其他線程占用臨界區(qū)對象,則調(diào)用Lock(),線程獲取臨界區(qū)。否則,線程被掛起,并放入到一個系統(tǒng)隊列中等待,直到當(dāng)前擁有的線程釋放了臨界區(qū)為止。
  3. 訪問臨界區(qū)結(jié)束后,使用Unlock()來釋放臨界區(qū)。
2.3 CCriticalSection在網(wǎng)狐框架中的使用
  1. 它為CCriticalSection專門定義了一個新類CWHDataLocker,其中增加了鎖定計數(shù)這個字段,在使用臨界區(qū)的時候,不單單是鎖定臨界區(qū),還會將鎖定計數(shù)+1,在解鎖的時候,會將鎖定計數(shù)-1
//變量定義
private:
    INT                             m_nLockCount;                   //鎖定計數(shù)
    CCriticalSection &              m_CriticalSection;              //鎖定對象


//構(gòu)造函數(shù)
CWHDataLocker::CWHDataLocker(CCriticalSection & CriticalSection, bool bLockAtOnce) 
    : m_CriticalSection(CriticalSection)
{
    //設(shè)置變量
    m_nLockCount=0;

    //鎖定對象
    if (bLockAtOnce==true)
    {
        Lock();
    }

    return;
}

//析構(gòu)函數(shù)
CWHDataLocker::~CWHDataLocker()
{
    //解除鎖定
    while (m_nLockCount>0)
    {
        UnLock();
    }

    return;
}

//鎖定函數(shù)
VOID CWHDataLocker::Lock()
{
    //鎖定對象
    m_CriticalSection.Lock();

    //設(shè)置變量
    m_nLockCount++;

    return;
}

//解鎖函數(shù)
VOID CWHDataLocker::UnLock()
{
    //效驗狀態(tài)
    ASSERT(m_nLockCount>0);
    if (m_nLockCount==0) return;

    //設(shè)置變量
    m_nLockCount--;

    //解除鎖定
    m_CriticalSection.Unlock();

    return;
}
  1. 在隊列服務(wù)中,我們可以看到該類的使用,在隊列中加入數(shù)據(jù)或者提取數(shù)據(jù)都使用了臨界區(qū)。因為臨界區(qū)在函數(shù)中實例化,所以在函數(shù)結(jié)束后會自動調(diào)用CWHDataLocker的析構(gòu)函數(shù)解除臨界區(qū)的鎖定
//加入數(shù)據(jù)
bool  CQueueService::AddToQueue(WORD wIdentifier,void *const pBuffer, WORD wDataSize)
{
    CWHDataLocker lock(m_CriticalSection);//
    m_DataQueue.InsertData(wIdentifier, pBuffer, wDataSize);
    PostQueuedCompletionStatus(m_hCompletionPort, wDataSize, (ULONG_PTR)this, NULL);
    return true;
}

//提取數(shù)據(jù)
bool CQueueService::GetData(tagDataHead & DataHead, void * pBuffer, WORD wBufferSize)
{
    CWHDataLocker lock(m_CriticalSection);//
    return m_DataQueue.DistillData(DataHead, pBuffer, wBufferSize);
}
  1. 網(wǎng)狐框架中大量使用了臨界區(qū):登錄服務(wù)器、游戲服務(wù)器、定時器引擎、隊列服務(wù)TCP引擎、異步引擎等等
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容