今天早上在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的用法
- 定義一個CCriticalSection類的全局對象,因為是全局對象,那么各個線程均可以訪問。
- 在訪問需要保護的資源或代碼之前,調(diào)用CCriticalSection類的成員Lock()獲得臨界區(qū)對象。
在線程中調(diào)用該函數(shù)來使線程獲得它所請求的臨界區(qū),如果此時沒有其他線程占用臨界區(qū)對象,則調(diào)用Lock(),線程獲取臨界區(qū)。否則,線程被掛起,并放入到一個系統(tǒng)隊列中等待,直到當(dāng)前擁有的線程釋放了臨界區(qū)為止。 - 訪問臨界區(qū)結(jié)束后,使用Unlock()來釋放臨界區(qū)。
2.3 CCriticalSection在網(wǎng)狐框架中的使用
- 它為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;
}
- 在隊列服務(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);
}
- 網(wǎng)狐框架中大量使用了臨界區(qū):登錄服務(wù)器、游戲服務(wù)器、定時器引擎、隊列服務(wù)TCP引擎、異步引擎等等