Using the semaphore object for thread synchronization
/* 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.
*/
// For WinXp as a target, change appropriately
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
#define MAX_SEM_COUNT 4
#define THREADCOUNT 6
// Handle to semaphore object
HANDLE ghSemaphore;
// Task counting
static int count = 0;
// Create thread function
DWORD WINAPI ThreadProc(LPVOID);
int wmain(void)
{
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(L"CreateSemaphore()failed, error: %d\n", GetLastError());
return 1;
}
else
wprintf(L"CreateSemaphore() should be fine!\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(L"CreateThread() failed, error: %d\n", GetLastError());
return 1;
}
else
wprintf(L"CreateThread() looks OK!\n");
}
// Wait for all threads to terminate
wprintf(L"Waiting all threads to terminate...\n");
WaitForMultipleObjects(THREADCOUNT, aThread, TRUE, INFINITE);
// Close thread and semaphore handles
wprintf(L"Closing all the thread and semaphore handles...\n");
for( i=0; i < THREADCOUNT; i++ )
CloseHandle(aThread[i]);
CloseHandle(ghSemaphore);
return 0;
}
DWORD WINAPI ThreadProc( LPVOID lpParam )
{
// lpParam not used in this example
UNREFERENCED_PARAMETER(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(L"Thread %d: wait succeeded...\n", GetCurrentThreadId());
bContinue=FALSE;
// Simulate thread spending time on task
wprintf(L"Completing task #%d....\n", count++);
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(L"ReleaseSemaphore() failed, error: %d\n", GetLastError());
}
else
wprintf(L"ReleaseSemaphore() is pretty fine!\n");
}
break;
// The semaphore was nonsignaled, so a time-out occurred.
case WAIT_TIMEOUT:
wprintf(L"Thread %d: wait timed out...\n", GetCurrentThreadId());
break;
}
}
return TRUE;
}
Output example:
CreateSemaphore() should be fine!
CreateThread() looks OK!
Thread 636: wait succeeded...
CreateThread() looks OK!
Completing task #0....
CreateThread() looks OK!
Thread 4952: wait succeeded...
Completing task #1....
CreateThread() looks OK!
Thread 4944: wait succeeded...
Completing task #2....
CreateThread() looks OK!
Thread 5200: wait succeeded...
Thread 5460: wait timed out...
CreateThread() looks OK!
Completing task #3....
Thread 5460: wait timed out...
Waiting all threads to terminate...
Thread 2448: wait timed out...
Thread 5460: wait timed out...
Thread 2448: wait timed out...
Thread 5460: wait timed out...
Thread 2448: wait timed out...
Thread 5460: wait timed out...
Thread 2448: wait timed out...
Thread 5460: wait timed out...
[TRIMMED]
Thread 5460: wait timed out...
Thread 2448: wait timed out...
Thread 5460: wait timed out...
Thread 2448: wait timed out...
Thread 5460: wait timed out...
Thread 2448: wait timed out...
Thread 5460: wait timed out...
Thread 2448: wait timed out...
Thread 5460: wait timed out...
Thread 2448: wait timed out...
Thread 5460: wait timed out...
Thread 2448: wait timed out...
Thread 5460: wait timed out...
Thread 2448: wait timed out...
Thread 5460: wait timed out...
Thread 2448: wait timed out...
Thread 5460: wait timed out...
Thread 2448: wait timed out...
Thread 5460: wait timed out...
Thread 2448: wait timed out...
Thread 5460: wait timed out...
Thread 2448: wait timed out...
Thread 5460: wait timed out...
Thread 2448: wait timed out...
Thread 5460: wait timed out...
Thread 2448: wait timed out...
Thread 5460: wait timed out...
Thread 2448: wait timed out...
Thread 5460: wait timed out...
Thread 2448: wait timed out...
Thread 5460: wait timed out...
Thread 2448: wait timed out...
Thread 5460: wait timed out...
Thread 2448: wait timed out...
Thread 5460: wait timed out...
Thread 2448: wait timed out...
Thread 5460: wait timed out...
[TRIMMED]
Thread 2448: wait timed out...
Thread 5460: wait timed out...
Thread 2448: wait timed out...
Thread 5460: wait timed out...
Thread 2448: wait timed out...
Thread 5460: wait timed out...
Thread 2448: wait timed out...
Thread 5460: wait timed out...
Thread 2448: wait timed out...
Thread 5460: wait timed out...
Thread 2448: wait timed out...
Thread 5460: wait timed out...
Thread 2448: wait timed out...
Thread 5460: wait timed out...
Thread 2448: wait timed out...
Thread 5460: wait timed out...
Thread 2448: wait timed out...
Thread 5460: wait timed out...
Thread 2448: wait timed out...
Thread 5460: wait timed out...
Thread 2448: wait timed out...
Thread 5460: wait timed out...
Thread 2448: wait timed out...
Thread 5460: wait timed out...
Thread 2448: wait timed out...
Thread 2448: wait timed out...
ReleaseSemaphore() is pretty fine!
ReleaseSemaphore() is pretty fine!
ReleaseSemaphore() is pretty fine!
ReleaseSemaphore() is pretty fine!
Thread 5460: wait timed out...
Thread 5460: wait succeeded...
Thread 2448: wait succeeded...
Completing task #4....
Completing task #5....
ReleaseSemaphore() is pretty fine!
ReleaseSemaphore() is pretty fine!
Closing all the thread and semaphore handles...
Compiler: Visual C++ Express Edition 2005
Compiled on Platform: Windows XP Pro SP2
Target platform: none, just for learning and fun
Header file: Standard and Windows
Additional library: Windows Platform SDK
Additional project setting: Set project to be compiled as C
Project -> your_project_name Properties -> Configuration Properties -> C/C++ -> Advanced -> Compiled As: Compiled as C Code (/TC)
Other info: non-CLR or unmanaged
To do: Using the semaphore for thread synchronization
To show: The Windows process and thread related functions