While binary semaphores can only have values between 0 and 1, counting semaphores can have a wider range of values. Some use cases for counting semaphores include simultaneous connections in a communication stack or static buffers from a memory pool.
For example, let's say we have a TCP/IP stack that supports multiple simultaneous TCP sessions, but the MCU only has enough RAM to support three simultaneous TCP sessions. This would be a perfect use case for a counting semaphore.
The counting semaphore for this application needs to be defined so that it has a maximum count of 3 and an initial value of 3 (three TCP sessions are available):
SemaphoreHandle_t semPtr = NULL;
semPtr = xSemaphoreCreateCounting( /*max count*/3, /*init count*/ 3);
if(semPtr != NULL)
The code that requests to open a TCP session would take semPtr, reducing its count by 1:
if(xSemaphoreTake( semPtr, /*timeoutTicks*/100) == pdPASS)
{
//resources for TCP session are available
}
else
{
//timed out waiting for session to become available
}
Whenever a TCP session is closed, the code closing the session gives semPtr, increasing its count by 1:
xSemaphoreGive( semPtr );
By using a counting semaphore, you can control access to a limited number of available TCP sessions. By doing this, we're accomplishing two things:
- Limiting the number of simultaneous TCP sessions, thus keeping resource usage in check.
- Providing time-bound access for creating a TCP session. This means the code is able to specify how long it will wait for a session to become available.
Counting semaphores are useful for controlling access to a shared resource when more than one instance is available.