Windows 平台下的同步机制 (4)– 信号量(Semaphore)

来源:互联网 发布:照片裁切软件 编辑:程序博客网 时间:2024/05/16 08:44

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 12HANDLE 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;}
原创粉丝点击