Good Morning AskPerf! Today is the last in our series on Windows Synchronization Mechanisms. Our topic today is Semaphore Objects. A semaphore object is a kernel-mode synchronization object that maintains a count between zero and a maximum specified value. Semaphores are similar to mutexes in that they allow exclusive access to a resource. What is unique about semaphores is that they use a resource counting mechanism. This allows a certain number of threads to access the resource. Now, given what we’ve discussed in our last few posts, this may seem contrary to everything we’ve said.
However, consider this scenario. Let’s say that we have a system with 3 USB ports. Since there are three ports, we want to allow three threads to concurrently access one of the available ports. What happens is that the semaphore is created with a maximum resource count of 3. As each thread tries to access the port, a check is made to see if the semaphore’s resource count is greater than zero. If it is, then the thread is allowed to access the port, and the resource count is decremented by 1. If the resource count reaches 0, then any thread that tries to acquire the semaphore is blocked until another thread releases the semaphore – and increments the resource count by 1. Normally the semaphore’s initial count is set to its maximum specified value, although there are instances where a semaphore’s value may initially be set to 0 in order to block access to the resource while an application initializes. In addition, it is possible for a thread to decrement the semaphore count multiple times if it repeatedly specifies the same semaphore object in its calls.
So, the simple principle for semaphores is that the resource count decrements by one when a thread acquires it and increments by one when a thread releases it. One point to remember is that the model for semaphores is not necessarily a FIFO (First In First Out) one. If there are multiple threads waiting for a semaphore, one of the waiting ones is selected. The wait order may be modified by kernel-mode APC (Asynchronous Procedure Call) routines.
That’s all for today – a short post, but an important one. Until next time …