windows多執行緒同步--訊號量

tenos發表於2014-03-14

推薦參考部落格:秒殺多執行緒第八篇 經典執行緒同步 訊號量Semaphore

 

首先先介紹和windows訊號量有關的兩個API:建立訊號量、釋放訊號量

 

HANDLE WINAPI CreateSemaphore(               msdn官網解釋
  _In_opt_  LPSECURITY_ATTRIBUTES lpSemaphoreAttributes
  _In_      LONG lInitialCount,
  _In_      LONG lMaximumCount,
  _In_opt_  LPCTSTR lpName
);
第一個引數:安全屬性,如果為NULL則是預設安全屬性
第二個引數:訊號量的初始值,要>=0且<=第三個引數
第三個引數:訊號量的最大值
第四個引數:訊號量的名稱
返回值:指向訊號量的控制程式碼,如果建立的訊號量和已有的訊號量重名,那麼返回已經存在的訊號量控制程式碼

 

BOOL WINAPI ReleaseSemaphore(             msdn官網解釋
  _In_       HANDLE hSemaphore,
  _In_       LONG lReleaseCount,
  _Out_opt_  LPLONG lpPreviousCount
);
第一個引數:訊號量控制程式碼
第二個引數:釋放後,訊號量增加的數目
第三個引數:訊號量增加前的值存放的地址,如果不需要則為NULL
返回值:釋放是否成功

 

以上兩個函式標頭檔案:windows.h (另外還有個函式OpenSemaphore()可以開啟其它程式建立的訊號量)                                      本文地址

 

下面通過一個例子來說明訊號量如何使用,這是一道IT公司筆試題:編寫一個程式,開啟3個執行緒,這3個執行緒的ID分別為A、B、C,每個執行緒將自己的ID在螢幕上列印10遍,要求輸出結果必須按ABC的順序顯示;如:ABCABC….依次遞推。

分析:這裡我們要讓三個執行緒按順序依次列印ABC,即當一個執行緒在列印A時,另外兩個執行緒不能夠列印,而且列印完A以後,接下來必須列印B。我們使用三個訊號量分別控制A B C的列印,列印完A就釋放B的訊號量,列印完B就釋放C的訊號量,列印完C就釋放A的訊號量。具體見下面程式碼:

 #include<string>
 #include<iostream>
 #include<process.h>
 #include<windows.h>
 using namespace std;
 HANDLE hsem1,hsem2,hsem3;

//執行緒繫結的函式返回值和引數是確定的,而且一定要__stdcall
unsigned __stdcall threadFunA(void *)
{
    for(int i = 0; i < 10; i++){
        WaitForSingleObject(hsem1, INFINITE);//等待訊號量
        cout<<"A";
        ReleaseSemaphore(hsem2, 1, NULL);//釋放訊號量
    }
    return 1;
}
unsigned __stdcall threadFunB(void *)
{
    for(int i = 0; i < 10; i++){
        WaitForSingleObject(hsem2, INFINITE);//等待訊號量
        cout<<"B";
        ReleaseSemaphore(hsem3, 1, NULL);//釋放訊號量
    }
    return 2;
}
unsigned __stdcall threadFunC(void *)
{
    for(int i = 0; i < 10; i++){
        WaitForSingleObject(hsem3, INFINITE);//等待訊號量
        cout<<"C";
        ReleaseSemaphore(hsem1, 1, NULL);//釋放訊號量
    }
    return 3;
}


int main()
{
    //建立訊號量
    hsem1 = CreateSemaphore(NULL, 1, 1, NULL);
    hsem2 = CreateSemaphore(NULL, 0, 1, NULL);
    hsem3 = CreateSemaphore(NULL, 0, 1, NULL);

    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);
    CloseHandle(hsem1);
    CloseHandle(hsem2);
    CloseHandle(hsem3);
}

 

訊號量沒有執行緒所有權屬性,即一個執行緒獲得某個訊號量後,在他釋放該訊號量之前,他不能再次進入訊號量保護的區域

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

相關文章