1. 程式人生 > >C++ 訊號量 多執行緒同步互斥

C++ 訊號量 多執行緒同步互斥

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">訊號量(Semaphores)   </span>
訊號量物件對執行緒的同步方式與前面幾種方法不同,訊號允許多個執行緒同時使用共享資源,這與作業系統中的PV操作相同。它指出了同時訪問共享資源的執行緒 最大數目。它允許多個執行緒在同一時刻訪問同一資源,但是需要限制在同一時刻訪問此資源的最大執行緒數目。在用CreateSemaphore()建立訊號量 時即要同時指出允許的最大資源計數和當前可用資源計數。一般是將當前可用資源計數設定為最大資源計數,每增加一個執行緒對共享資源的訪問,當前可用資源計數 就會減1,只要當前可用資源計數是大於0的,就可以發出訊號量訊號。但是當前可用計數減小到0時則說明當前佔用資源的執行緒數已經達到了所允許的最大數目, 不能在允許其他執行緒的進入,此時的訊號量訊號將無法發出。執行緒在處理完共享資源後,應在離開的同時通過ReleaseSemaphore()函式將當前可 用資源計數加1。在任何時候當前可用資源計數決不可能大於最大資源計數。  
PV操作及訊號量的概念都是由荷蘭科學家E.W.Dijkstra提出的。訊號量S是一個整數,S大於等於零時代表可供併發程序使用的資源實體數,但S小於零時則表示正在等待使用共享資源的程序數。  P操作 申請資源:  (1)S減1;  
(2)若S減1後仍大於等於零,則程序繼續執行;  
(3)若S減1後小於零,則該程序被阻塞後進入與該訊號相對應的佇列中,然後轉入程序排程。  
V操作 釋放資源:  (1)S加1;  
(2)若相加結果大於零,則程序繼續執行;  
(3)若相加結果小於等於零,則從該訊號的等待佇列中喚醒一個等待程序,然後再返回原程序繼續執行或轉入程序排程。   
訊號量包含的幾個操作原語:  

CreateSemaphore() 建立一個訊號量  

OpenSemaphore() 開啟一個訊號量  

ReleaseSemaphore() 釋放訊號量 

WaitForSingleObject() 等待訊號量  

#include <Windows.h>
#include <stdio.h>

HANDLE hSemaphore = NULL;
const char* strSemaphoreName = "MySemaphore";
const int threads_num = 50;
HANDLE Threads[threads_num];
bool bExitThreads = FALSE;

void WINAPI ThreadFun(void* param)
{
    printf("執行緒 %u 開始執行\n", GetCurrentThreadId());
    WaitForSingleObject(hSemaphore,INFINITE);
    printf("執行緒 %u 獲得訊號量,繼續執行\n", GetCurrentThreadId());
    while(!bExitThreads)
    {
            Sleep(10);
    }
    long dwSem = 0;
    if (!ReleaseSemaphore(hSemaphore, 1, &dwSem))
    {
        if (0 == GetLastError())
        {
            printf("當前可用資源數:20\n");
            return;
        }
    }
    
    printf("當前可用資源數:%u\n", dwSem);
}

void creatThreads()
{
    DWORD dwThreadID = 0;
    for (int i =0; i < threads_num; ++i)
    {
        Threads[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadFun, NULL, 0, &dwThreadID);
        if (!Threads[i])
        {
            printf("建立執行緒失敗!\n");
        }
        printf("執行緒 %u 建立成功\n", dwThreadID);
    }
}

void  main()
{
    hSemaphore = CreateSemaphoreA(NULL, 0, 20, strSemaphoreName);
    if(NULL == (hSemaphore = OpenSemaphoreA(SEMAPHORE_MODIFY_STATE , FALSE, strSemaphoreName)))
    {
        printf("開啟訊號量物件失敗 , 錯誤ID:%u\n", GetLastError());
        return;
    }

    creatThreads();
    bExitThreads = true;
    WaitForMultipleObjects(threads_num, Threads, TRUE, INFINITE);

}