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:
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.
#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;
}