線程的同步(一)---臨界區

當多個線程訪問一個獨佔性共享資源時,可以使用臨界區對象。任一時刻只有一個線程可以擁有臨界區對象,擁有臨界區的線程可以訪問被保護起來的資源或代碼段,其他希望進入臨界區的線程將被掛起等待,直到擁有臨界區的線程放棄臨界區時爲止,這樣就保證了不會在同一時刻出現多個線程訪問共享資源。

以下的臨界區用法中,CRITICAL_SECTION一般是在SDK下使用,而CCriticalSection類是MFCCRITICAL_SECTION使用的封裝。如果是在MFC下編程,推薦使用CCriticalSection類。

1 使用CRITICAL_SECTION結構

使用方法:

      CRITICAL_SECTION g_cs;

      EnterCriticalSection(&g_cs);

      ……         //要加鎖的代碼段

      LeaveCriticalSection(&g_cs);

1) 該結構的使用有兩個要求:

第一個要求是,需要訪問該資源的所有線程都必須知道負責保護資源的CRITICAL_SECTION結構的地址,你可以使用你喜歡的任何機制來獲得這些線程的這個地址;

第二個要求是, CRITICAL_SECTION結構中的成員應該在任何線程試圖訪問被保護的資源之前初始化。該結構通過調用下面的函數來進行初始化:

void InitializeCriticalSection(PCRITICAL_SECTION pcs);

該函數用於對(pcs指向的)CRITICAL_SECTION結構的各個成員進行初始化。由於該函數只是設置了某些成員變量。因此它的運行不會失敗,並且它的原型採用了void的返回值。該函數必須在任何線程調用EnterCriticalSection函數之前被調用。Platform SDK的文檔清楚地說明,如果一個線程試圖進入一個未初始化的CRITICAL_SECTION,那麼結果將是很難預計的。當知道進程的線程不再試圖訪問共享資源時,應該通過調用下面的函數來清除該CRITICAL_SECTION結構:

void DeleteCriticalSection(PCRITICAL_SECTION pcs);

DeleteCriticalSection函數用於對該結構中的成員變量進行刪除。當然,如果有任何線程仍然使用關鍵代碼段,那麼不應該刪除該代碼段。同樣, Platform SDK文檔清楚地說明如果刪除了關鍵代碼段,其結果就無法知道。

2) EnterCriticalSection負責進行下列測試:

如果沒有線程訪問該資源,EnterCriticalSection便更新成員變量,以指明調用線程已被賦予訪問權並立即返回,使該線程能夠繼續運行(訪問該資源)。

• 如果成員變量指明,調用線程已經被賦予對資源的訪問權,那麼EnterCriticalSection便更新這些變量,以指明調用線程多少次被賦予訪問權並立即返回,使該線程能夠繼續運行。這種情況很少出現,並且只有當線程在一行中兩次調用EnterCriticalSection而不影響對LeaveCriticalSection的調用時,纔會出現這種情況。

• 如果成員變量指明,一個線程(除了調用線程之外)已被賦予對資源的訪問權,那麼EnterCriticalSection將調用線程置於等待狀態。這種情況是極好的,因爲等待的線程不會浪費任何CPU時間。系統能夠記住該線程想要訪問該資源並且自動更新CRITICAL_SECTION的成員變量,一旦目前訪問該資源的線程調用LeaveCriticalSection函數,該線程就處於可調度狀態。

 

2 使用MFCCCriticalSection

1)定義CCriticalSection類的一個全局對象(以使各個線程均能訪問),如:

         CCriticalSection critical_section

2)在訪問需要保護的資源或代碼之前,調用CCriticalSection類的成員Lock()函數獲得臨界區對象:

         critical_section.Lock();

在線程中調用該函數來使線程獲得它所請求的臨界區。如果此時沒有其它線程佔有臨界區對象,則調用Lock()的線程獲得臨界區;否則,線程將被掛起,並放入到一個系統隊列中等待,直到當前擁有臨界區的線程釋放了臨界區時爲止。

3)訪問臨界區完畢後,使用CCriticalSection的成員函數Unlock()來釋放臨界區:

         critical_section.Unlock();

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章