windows多執行緒同步--臨界區

tenos發表於2014-03-14

推薦參考部落格:秒殺多執行緒第五篇 經典執行緒同步 關鍵段CS

 

關於臨界區的觀念,一般作業系統書上面都有。

適用範圍:它只能同步一個程式中的執行緒,不能跨程式同步。一般用它來做單個程式內的程式碼快同步,效率比較高

windows中與臨界區有關的結構是 CRITICAL_SECTION,關於該結構體的內部結構可參考here

使用時,主執行緒中要先初始化臨界區,最後要刪除臨界區,具體使用見下面程式碼:

                                                                              本文地址

從一個例子來說明:假設有三個執行緒都需要使用印表機,我們可以把列印的程式碼放到臨界區,這樣就可以保證每次只有一個執行緒在使用印表機。

 

 #include<string>
 #include<iostream>
 #include<process.h>
 #include<windows.h>
 using namespace std;

 //定義一個臨界區
 CRITICAL_SECTION g_cs;

//執行緒繫結的函式返回值和引數是確定的,而且一定要__stdcall
unsigned __stdcall threadFun(void *param)
{
    EnterCriticalSection(&g_cs);//進入臨界區,如果有其他執行緒則等待
    cout<<*(string *)(param)<<endl;
    LeaveCriticalSection(&g_cs);//退出臨界區,其他執行緒可以進來了
    return 1;
}


int main()
{
    //初始化臨界區
    InitializeCriticalSection(&g_cs);

    HANDLE hth1, hth2, hth3;
    string s1 = "first", s2 = "second", s3 = "third";

    //建立執行緒
    hth1 = (HANDLE)_beginthreadex(NULL, 0, threadFun, &s1, 0, NULL);
    hth2 = (HANDLE)_beginthreadex(NULL, 0, threadFun, &s2, 0, NULL);
    hth3 = (HANDLE)_beginthreadex(NULL, 0, threadFun, &s3, 0, NULL);

    //等待子執行緒結束
    WaitForSingleObject(hth1, INFINITE);
    WaitForSingleObject(hth2, INFINITE);
    WaitForSingleObject(hth3, INFINITE);

    //一定要記得關閉執行緒控制程式碼
    CloseHandle(hth1);
    CloseHandle(hth2);
    CloseHandle(hth3);

    //刪除臨界區
    DeleteCriticalSection(&g_cs);
}

 

再看另外一個問題:編寫一個程式,開啟3個執行緒,這3個執行緒的ID分別為A、B、C,每個執行緒將自己的ID在螢幕上列印10遍,要求輸出結果必須按ABC的順序顯示;如:ABCABC….依次遞推, 仿照文章windows多執行緒同步--訊號量中的程式碼,我們把訊號量替換成臨界區。

 #include<string>
 #include<iostream>
 #include<process.h>
 #include<windows.h>
 using namespace std;
 //宣告3個臨界區
CRITICAL_SECTION  g_cs1, g_cs2, g_cs3;

//執行緒繫結的函式返回值和引數是確定的,而且一定要__stdcall
unsigned __stdcall threadFunA(void *)
{
    for(int i = 0; i < 10; i++){
        EnterCriticalSection(&g_cs1);//進入臨界區
        cout<<"A";
        LeaveCriticalSection(&g_cs2);//離開臨界區
    }
    return 1;
}
unsigned __stdcall threadFunB(void *)
{
    for(int i = 0; i < 10; i++){
        EnterCriticalSection(&g_cs2);//進入臨界區
        cout<<"B";
        LeaveCriticalSection(&g_cs3);//離開臨界區
    }
    return 2;
}
unsigned __stdcall threadFunC(void *)
{
    for(int i = 0; i < 10; i++){
        EnterCriticalSection(&g_cs3);//進入臨界區
        cout<<"C";
        LeaveCriticalSection(&g_cs1);//離開臨界區
    }
    return 3;
}


int main()
{
    //初始化臨界區
    InitializeCriticalSection(&g_cs1);
    InitializeCriticalSection(&g_cs2);
    InitializeCriticalSection(&g_cs3);

    HANDLE hth1, hth2, hth3;

    //建立執行緒
    hth1 = (HANDLE)_beginthreadex(NULL, 0, threadFunA, NULL, 0, NULL);
    hth2 = (HANDLE)_beginthreadex(NULL, 0, threadFunB, NULL, 0, NULL);
    hth3 = (HANDLE)_beginthreadex(NULL, 0, threadFunC, NULL, 0, NULL);

    //等待子執行緒結束
    WaitForSingleObject(hth1, INFINITE);
    WaitForSingleObject(hth2, INFINITE);
    WaitForSingleObject(hth3, INFINITE);

    //一定要記得關閉執行緒控制程式碼
    CloseHandle(hth1);
    CloseHandle(hth2);
    CloseHandle(hth3);

    //刪除臨界區
    DeleteCriticalSection(&g_cs1);
    DeleteCriticalSection(&g_cs2);
    DeleteCriticalSection(&g_cs3);
}

 

image

為什麼會這樣呢,因為臨界區有所有權的概念,即某個執行緒進入臨界區後,就擁有該臨界區的所有權,在他離開臨界區之前,他可以無限次的再次進入該臨界區,上例中執行緒A獲得臨界區1的所有權後,線上程C呼叫LeaveCriticalSection(&g_cs1)之前,A是可以無限次的進入臨界區1的。利用訊號量之所以可以實現題目的要求,是因為訊號量沒有所有權的概念,某個執行緒獲得訊號量後,如果訊號量的值為0,那麼他一定要等到訊號量被釋放時,才能再次獲得

關於臨界區的詳細解釋清參考秒殺多執行緒第五篇 經典執行緒同步 關鍵段CS

 

【版權宣告】轉載請註明出處http://www.cnblogs.com/TenosDoIt/p/3601308.html

相關文章