Windows 平臺下的同步機制 (4)– 信號量(Semaphore)

Windows 平臺下的同步機制 (4)– 信號量(Semaphore)

Semaphore是旗語的意思,在Windows中,Semaphore對象用來控制對資源的併發訪問數。Semaphore對象具有一個計數值,當值大於0時,Semaphore被置信號,當計數值等於0時,Semaphore被清除信號。每次針對Semaphore的wait functions返回時,計數值被減1,調用ReleaseSemaphore可以將計數值增加 lReleaseCount 參數值指定的值。

CreateSemaphore函數用於創建一個Semaphore

HANDLE CreateSemaphore(
LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
LONG lInitialCount,
LONG lMaximumCount,
LPCTSTR lpName
);

lpSemaphoreAttributes爲安全屬性,
lInitialCount爲Semaphore的初始值,
lMaximumCount爲最大值,
lpName爲Semaphore對象的名字,NULL表示創建匿名Semaphore

此外還可以調用OpenSemaphore來打開已經創建的非匿名Semaphore

HANDLE OpenSemaphore(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
LPCTSTR lpName
);

調用ReleaseSemaphore增加Semaphore計算值

BOOL ReleaseSemaphore(
HANDLE hSemaphore,
LONG lReleaseCount,
LPLONG lpPreviousCount
);

lpReleaseCount參數表示要增加的數值,
lpPreviousCount參數用於返回之前的計算值,如果不需要可以設置爲NULL

比如我們要控制到服務器的連接數不超過10個,可以創建一個Semaphore,初值爲10,每當要連接到服務器時,使用WaitForSingleObject請求Semaphore,當成功返回後再嘗試連接到服務器,當連接失敗或連接使用完後釋放時,調用ReleaseSemaphore增加Semaphore計數值。

看個例子,popo現在好像在本機只能運行三個實例,mutex可以讓程序只是運行一個實例,下面我通過信號量機制讓程序像popo一樣運行三個實例。

#include "stdafx.h"
#include <windows.h>
#include <iostream>
using namespace std;

const int MAX_RUNNUM = 3;  //最多運行實例個數
void PrintInfo()
{
    char c;
    cout << "run program" << endl;
    cout << "input s to exit program!" << endl;
    while (1)
    {
        cin >> c;
        if (c == ‘s’)
        {
            break;
        }
        Sleep(10);
    }
}
int main(int argc, char* argv[])
{
    HANDLE hSe = CreateSemaphore(NULL, MAX_RUNNUM, MAX_RUNNUM, "semaphore_test");
    DWORD ret = 0;
    if (hSe == NULL)
    {
        cout << "createsemaphore failed with code: " << GetLastError() << endl;
        return -1;
    }
    ret = WaitForSingleObject(hSe, 1000);
    if (ret == WAIT_TIMEOUT)
    {
        cout << "you have runned " << MAX_RUNNUM << " program!" << endl;
        ret = WaitForSingleObject(hSe, INFINITE);
    }
    PrintInfo();
    ReleaseSemaphore(hSe, 1, NULL);
    CloseHandle(hSe);
    return 0;
}

From MSDN:

Using Semaphore Objects

The following example uses a semaphore object to limit the number of threads that can perform a particular task. First, it uses the CreateSemaphore function to create the semaphore and to specify initial and maximum counts, then it uses the CreateThread function to create the threads.

Before a thread attempts to perform the task, it uses the WaitForSingleObject function to determine whether the semaphore’s current count permits it to do so. The wait function’s time-out parameter is set to zero, so the function returns immediately if the semaphore is in the nonsignaled state. WaitForSingleObject decrements the semaphore’s count by one.

When a thread completes the task, it uses the ReleaseSemaphore function to increment the semaphore’s count, thus enabling another waiting thread to perform the task.

Copy

#include <windows.h>
#include <stdio.h>

#define MAX_SEM_COUNT 10
#define THREADCOUNT 12

HANDLE ghSemaphore;

DWORD WINAPI ThreadProc( LPVOID );

void main()
{
    HANDLE aThread[THREADCOUNT];
    DWORD ThreadID;
    int i;

    // Create a semaphore with initial and max counts of MAX_SEM_COUNT

    ghSemaphore = CreateSemaphore(
        NULL,           // default security attributes
        MAX_SEM_COUNT,  // initial count
        MAX_SEM_COUNT,  // maximum count
        NULL);          // unnamed semaphore

    if (ghSemaphore == NULL)
    {
        printf("CreateSemaphore error: %dn", GetLastError());
        return;
    }

    // Create worker threads

    for( i=0; i < THREADCOUNT; i++ )
    {
        aThread[i] = CreateThread(
                     NULL,       // default security attributes
                     0,          // default stack size
                     (LPTHREAD_START_ROUTINE) ThreadProc,
                     NULL,       // no thread function arguments
                     0,          // default creation flags
                     &ThreadID); // receive thread identifier

        if( aThread[i] == NULL )
        {
            printf("CreateThread error: %dn", GetLastError());
            return;
        }
    }

    // Wait for all threads to terminate

    WaitForMultipleObjects(THREADCOUNT, aThread, TRUE, INFINITE);

    // Close thread and semaphore handles

    for( i=0; i < THREADCOUNT; i++ )
        CloseHandle(aThread[i]);

    CloseHandle(ghSemaphore);
}

DWORD WINAPI ThreadProc( LPVOID lpParam )
{
    DWORD dwWaitResult;
    BOOL bContinue=TRUE;

    while(bContinue)
    {
        // Try to enter the semaphore gate.

        dwWaitResult = WaitForSingleObject(
            ghSemaphore,   // handle to semaphore
            0L);           // zero-second time-out interval

        switch (dwWaitResult)
        {
            // The semaphore object was signaled.
            case WAIT_OBJECT_0:
                // TODO: Perform task
                printf("Thread %d: wait succeededn", GetCurrentThreadId());
                bContinue=FALSE;            

                // Simulate thread spending time on task
                Sleep(5);

                // Release the semaphore when task is finished

                if (!ReleaseSemaphore(
                        ghSemaphore,  // handle to semaphore
                        1,            // increase count by one
                        NULL) )       // not interested in previous count
                {
                    printf("ReleaseSemaphore error: %dn", GetLastError());
                }
                break; 

            // The semaphore was nonsignaled, so a time-out occurred.
            case WAIT_TIMEOUT:
                printf("Thread %d: wait timed outn", GetCurrentThreadId());
                break;
        }
    }
    return TRUE;
}


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