Semaphore objects are specific synchronization objects that maintain a counter that lock/unlock the object on reaching specific predefined count. The counter make the object specific and different from other synchronization objects such as critical sections, mutexes, events. After years of software development with a horde of threads and events it is the first time I needed to look towards semaphore.
While it’s quite clear what exactly it does, a tiny sample would never hurt to understand thing better. Good news is that ATL core classes offer a CSemaphore class (surprisingly not documented in MSDN).
Semaphore magic goes below:
D:\...\SemaphoreSample01\Release>SemaphoreSample01.exe
Time 0000, Thread 05208: Main thread is initializing...
Time 0000, Thread 04132: Worker thread is initializing...
Time 0000, Thread 04132: Wait result 0
Time 0000, Thread 03284: Worker thread is initializing...
Time 0000, Thread 04132: Delay 4041
Time 0000, Thread 01360: Worker thread is initializing...
Time 0000, Thread 06020: Worker thread is initializing...
Time 0000, Thread 02444: Worker thread is initializing...
Time 0000, Thread 05392: Worker thread is initializing...
Time 0000, Thread 01036: Worker thread is initializing...
Time 0000, Thread 05088: Worker thread is initializing...
Time 0000, Thread 03284: Wait result 0
Time 0000, Thread 01360: Wait result 0
Time 0000, Thread 06020: Wait result 0
Time 0016, Thread 03284: Delay 4467
Time 0016, Thread 01360: Delay 4500
Time 0016, Thread 06020: Delay 5724
Time 4047, Thread 04132: Semaphore is about to be released
Time 4047, Thread 04132: Semaphore released, nOldCount 0
Time 4047, Thread 02444: Wait result 0
Time 4047, Thread 04132: Worker thread is terminating...
Time 4047, Thread 02444: Delay 5358
Time 4485, Thread 03284: Semaphore is about to be released
Time 4485, Thread 05392: Wait result 0
Time 4485, Thread 03284: Semaphore released, nOldCount 0
Time 4485, Thread 05392: Delay 4334
Time 4485, Thread 03284: Worker thread is terminating...
Time 4516, Thread 01360: Semaphore is about to be released
Time 4516, Thread 01036: Wait result 0
Time 4516, Thread 01360: Semaphore released, nOldCount 0
Time 4516, Thread 01036: Delay 5169
Time 4516, Thread 01360: Worker thread is terminating...
Time 5000, Thread 05088: Wait result 258
Time 5000, Thread 05088: Worker thread is terminating...
Time 5735, Thread 06020: Semaphore is about to be released
Time 5735, Thread 06020: Semaphore released, nOldCount 0
Time 5735, Thread 06020: Worker thread is terminating...
Time 8813, Thread 05392: Semaphore is about to be released
Time 8813, Thread 05392: Semaphore released, nOldCount 1
Time 8829, Thread 05392: Worker thread is terminating...
Time 9407, Thread 02444: Semaphore is about to be released
Time 9407, Thread 02444: Semaphore released, nOldCount 2
Time 9407, Thread 02444: Worker thread is terminating...
Time 9688, Thread 01036: Semaphore is about to be released
Time 9688, Thread 01036: Semaphore released, nOldCount 3
Time 9688, Thread 01036: Worker thread is terminating...
Time 10000, Thread 05208: Main thread is terminating...
The sample creates a semaphore object with a counter value of 4 (g_nSemaphoreCount) and creates 8 (g_nThreadCount) threads to synchronize on this semaphore with a timeout value of 5 seconds (g_nSemaphoreWaitTimeout).
Semaphore would satisfy four requests according to its counter value and the rest of the threads would timeout on wait function call unless any of the successful threads release the lock.
A successful thread chooses time interval during which it holds the lock pseudo-randomly between 4 and 6 seconds (g_nFixedSemaphoreLockDelay, g_nRandomSemaphoreLockDelay). The delays are 4041 ms, 4467 ms, etc. asquoted above.
Note that as soon as first thread that held the lock for 4041 ms releases it, because 4041 is less than 5000 then another thread is on time getting a lock on the semaphore too.
Thus four threads are successful in waiting on semaphore from the start, 3 more threads locked the object before timeout value as soon as other threads release semaphore and the 8th thread failed to wait with a timeout result (Wait result 258).
This is how semaphore works.
Visual C++.NET 2005 source code can be downloaded here, compiled binary – here.