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

    技术2022-07-04  134

    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 #include 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 CreateThreadfunction 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 #include #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; }

    Further reading:

    1.Windows 平台下的同步机制 (1)– 临界区(CriticalSection)

    2.Windows 平台下的同步机制 (2)– 互斥体(Mutex)

    3.Windows 平台下的同步机制 (3)– 事件(Event)

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

    5.《windows核心编程》学习笔记(一)内核对象

    Reference:

    1.http://www.chinaitpower.com/A200507/2005-07-27/176735.html

    2.http://www.cppblog.com/wangjt/archive/2008/02/01/42362.aspx

    3.http://msdn.microsoft.com/en-us/library/ms686946.aspx


    最新回复(0)