臨界區

臨界區

臨界區指的是一個訪問共用資源(例如:共用設備或是共用存儲器)的程式片段,而這些共用資源又無法同時被多個執行緒訪問的特性。當有執行緒進入臨界區段時,其他執行緒或是進程必須等待(例如:bounded waiting 等待法),有一些同步的機制必須在臨界區段的進入點與離開點實現,以確保這些共用資源是被互斥獲得使用,例如:semaphore。只能被單一執行緒訪問的設備,例如:印表機

基本介紹

簡介,程式調度法則,執行緒同步問題,臨界區存在的幾個問題,

簡介

每個進程中訪問臨界資源的那段代碼稱為臨界區(Critical Section)(臨界資源是一次僅允許一個進程使用的共享資源)。每次只準許一個進程進入臨界區,進入後不允許其他進程進入。不論是硬體臨界資源,還是軟體臨界資源,多個進程必須互斥地對它進行訪問。
多個進程中涉及到同一個臨界資源的臨界區稱為相關臨界區。.

程式調度法則

進程進入臨界區的調度原則是:
1、如果有若干進程要求進入空閒的臨界區,一次僅允許一個進程進入。
2、任何時候,處於臨界區內的進程不可多於一個。如已有進程進入自己的臨界區,則其它所有試圖進入臨界區的進程必須等待。
3、進入臨界區的進程要在有限時間內退出,以便其它進程能及時進入自己的臨界區。
4、如果進程不能進入自己的臨界區,則應讓出CPU,避免進程出現“忙等”現象。

執行緒同步問題

有多個執行緒試圖同時訪問臨界區,那么在有一個執行緒進入後其他所有試圖訪問此臨界區的執行緒將被掛起,並一直持續到進入臨界區的執行緒離開。臨界區在被釋放後,其他執行緒可以繼續搶占,並以此達到用原子方式操作共享資源的目的。
臨界區在使用時以CRITICAL_SECTION結構對象保護共享資源,並分別用EnterCriticalSection()和LeaveCriticalSection()函式去標識和釋放一個臨界區。所用到的CRITICAL_SECTION結構對象必須經過InitializeCriticalSection()的初始化後才能使用,而且必須確保所有執行緒中的任何試圖訪問此共享資源的代碼都處在此臨界區的保護之下。否則臨界區將不會起到應有的作用,共享資源依然有被破壞的可能。
下面通過一段代碼展示了臨界區在保護多執行緒訪問的共享資源中的作用。通過兩個執行緒來分別對全局變數g_cArray[10]進行寫入操作,用臨界區結構對象g_cs來保持執行緒的同步,並在開啟執行緒前對其進行初始化。為了使實驗效果更加明顯,體現出臨界區的作用,線上程函式對共享資源g_cArray[10]的寫入時,以Sleep()函式延遲1毫秒,使其他執行緒同其搶占CPU的可能性增大。如果不使用臨界區對其進行保護,則共享資源數據將被破壞(參見圖1(a)所示計算結果),而使用臨界區對執行緒保持同步後則可以得到正確的結果(參見圖1(b)所示計算結果)。
代碼實現清單附下:
圖一圖一
// 臨界區結構對象CRITICAL_SECTION g_cs;// 共享資源char g_cArray[10];UINT ThreadProc10(LPVOID pParam){    // 進入臨界區    EnterCriticalSection(&g_cs);    // 對共享資源進行寫入操作    for (int i = 0; i < 10; i++)    {    g_cArray[i]  = a;    Sleep(1);    }    // 離開臨界區    LeaveCriticalSection(&g_cs);    return 0;}UINT ThreadProc11(LPVOID pParam){    // 進入臨界區    EnterCriticalSection(&g_cs);    // 對共享資源進行寫入操作    for (int i = 0; i < 10; i++)    {        g_cArray[10 - i - 1] = b;        Sleep(1);    }    // 離開臨界區    LeaveCriticalSection(&g_cs);    return 0;}……void CSample08View::OnCriticalSection(){    // 初始化臨界區    InitializeCriticalSection(&g_cs);    // 啟動執行緒    AfxBeginThread(ThreadProc10, NULL);    AfxBeginThread(ThreadProc11, NULL);    // 等待計算完畢    Sleep(300);    // 報告計算結果    CString sResult = CString(g_cArray);    AfxMessageBox(sResult);}

臨界區存在的幾個問題

在使用臨界區時,一般不允許其運行時間過長,只要進入臨界區的執行緒還沒有離開,其他所有試圖進入此臨界區的執行緒都會被掛起而進入到等待狀態,並會在一定程度上影響程式的運行性能。尤其需要注意的是不要將等待用戶輸入或是其他一些外界干預的操作包含到臨界區。如果進入了臨界區卻一直沒有釋放,同樣也會引起其他執行緒的長時間等待。換句話說,在執行了EnterCriticalSection()語句進入臨界區後無論發生什麼,必須確保與之匹配的LeaveCriticalSection()都能夠被執行到。可以通過添加結構化異常處理代碼來確保LeaveCriticalSection()語句的執行。雖然臨界區同步速度很快,但卻只能用來同步本進程內的執行緒,而不可用來同步多個進程中的執行緒。
1、 臨界區的退出,不會檢測是否是已經進入的執行緒,也就是說,我可以在A執行緒中調用進入臨界區函式,在B執行緒調用退出臨界區的函式,同樣是成功;
2、 我在測試臨界區的時候,如果我沒有調用進入臨界區的函式,直接退出的話,系統沒有進行判斷,但是計數發現了改變,此時此臨界區就再也用不了了,因為結構中的數據已經亂掉了。
解決方法如下:
ypedef class mutex_lock
{
public:
mutex_lock()
: LockCount(-1)
, hEvent(0)
{
}
~mutex_lock()
{
if(NULL != this->hEvent)
{
CloseHandle(this->hEvent);
}
this->hEvent = NULL;
this->LockCount = -1;
}
long GetLock();
long ReleaseLock();
private:
mutex_lock(mutex_lock&);
long LockCount;
HANDLE hEvent;
} MUTEXLOCK, *LPMUTEXLOCK;
long mutex_lock::GetLock()
{
__asm
{
movebx, [this];//把基址保存在ebx中
lock incdword ptr [ebx];//對LockCount進行加鎖加,保證多CPU時的唯一性,
jeLRET1;//如果LockCount加1為0的話,表示沒有人在使用資源,同時利用上面的互斥加對資源進行占用。
cmpdword ptr [ebx+4], 0;//此時LockCount加1大於0的情況,表示已有人使用此資源,要對此資源進行加核心鎖
jneL1;//如果平常沒有創建核心鎖,則進行創始一個
push 0;
push 0;
push 0;
push 0;
call dword ptr [CreateEvent];
movedx, eax;//創建記憶體鎖成功後,在同樣對hEvent變數進行互斥比較後替換,以處理多個執行緒同時對此值進行替換的情況,保證只有一個能夠成功替換
moveax, 0;
lock cmpxchg dword ptr [ebx+4], edx; //互斥比較替換
jeL1;
push edx;//如果已經被別人替換過了,需要把自己創建的核心鎖釋放
call dword ptr [CloseHandle];
L1:
push INFINITE;
push [ebx+4];
call dword ptr [WaitForSingleObject]; // 在核心級進行等待
LRET1:
moveax, 0
}
}
long mutex_lock::ReleaseLock()
{
__asm
{
movebx, [this];//把基址保存在ebx中
moveax, -1;
lock xadd dword ptr [ebx], eax; //進行交換自減交換操作,運行後,eax中是第一運算元先前的值,此值用會返回用來判斷是否多調用了ReleaseLock
jlLRET2;//沒有別的執行緒占用資源,直接返回,用戶可以通過返回值,分析是否失敗
cmpdword ptr [ebx+4], 0;//有別的執行緒在等待,檢查核心鎖,如果沒有則進行創建
jneL2;
push 0;
push 0;
push 0;
push 0;
call dword ptr [CreateEvent];
movedx, eax;
moveax, 0;
lock cmpxchg dword ptr [ebx+4], edx; //互斥替換核心鎖句柄
jeL2;//已經有核心鎖了,把自已申請的關閉
push edx;
call dword ptr [CloseHandle];
L2:
push [ebx+4];//設計信號,喚醒一個執行緒
call dword ptr [SetEvent];
moveax, 0;
LRET2:
}
}

相關詞條

熱門詞條

聯絡我們