Using Semaphore Objects Program Example
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.
Create a new empty Win32 console application project. Give a suitable project name and change the project location if needed.
Then, add the source file and give it a suitable name.
Next, add the following source code.
#include <windows.h>
#include <stdio.h>
#define MAX_SEM_COUNT 10
#define THREADCOUNT 12
HANDLE ghSemaphore;
DWORD WINAPI ThreadProc(LPVOID);
void wmain()
{
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)
{
wprintf(LCreateSemaphore() error %d\n, GetLastError());
return;
}
else
wprintf(LCreateSemaphore() is OK\n);
// 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 )
{
wprintf(LCreateThread() error %d\n, GetLastError());
return;
}
else
wprintf(LThread %d with ID %d was created...\n, i, ThreadID);
}
// Wait for all threads to terminate
wprintf(LWaiting all the threads to terminate...\n);
WaitForMultipleObjects(THREADCOUNT, aThread, TRUE, INFINITE);
// Close thread and semaphore handles
for( i=0; i < THREADCOUNT; i++ )
{
if(CloseHandle(aThread[i]) != 0)
wprintf(LHandle to thread %i was closed!\n, i);
else
wprintf(LFailed to close the thread %i handle, error %d\n, i, GetLastError());
}
if(CloseHandle(ghSemaphore) != 0)
wprintf(LHandle to Semaphore object was closed!\n, i);
else
wprintf(LFailed to close the Semaphore object handle, error %d\n, GetLastError());
}
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
wprintf(LThread %d: wait succeeded...\n, 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
{
wprintf(LReleaseSemaphore error %d\n, GetLastError());
}
break;
// The semaphore was nonsignaled, so a time-out occurred.
case WAIT_TIMEOUT:
wprintf(LThread %d: wait timed out...\n, GetCurrentThreadId());
break;
}
}
return TRUE;
}
Build and run the project. The following screenshots are the sample outputs.