4.3.2 Semaphore
Semaphores are used for synchronization and to control access to shared resources between tasks. A semaphore can either be binary or counting and is essentially just a non-negative integer count.
A binary semaphore is initialized to 1 and can be used to guard a
resource that can only be handled by one task at a time. When a task takes the
resource, the semaphore is decremented to 0. If another task then wants to use the
resource and sees that the semaphore is 0, it blocks. When the first task is
finished using the resource, the semaphore is incremented and is thus available to
other tasks. A binary semaphore can be created with SemaphoreHandle_t
semaphoreName = xSemaphoreCreateBinary(void)
.
A counting semaphore works in the same manner, but for resources that
can be used by multiple tasks at once. For example, if you have a parking garage
with room for 10 cars, you can allow 10 semaphore access. Every time a car enters,
the semaphore will be decremented by 1 until it reaches 0 and no one is allowed
entrance before someone leaves. A counting semaphore should be initialized to the
number of tasks that can have concurrent access to the resource and is created
with SemaphoreHandle_t semaphoreName = xSemaphoreCreateCounting(maxCount,
initialCount)
.
When a task wants a resource protected by a semaphore, it calls the
function xSemaphoreTake(semaphoreName, ticksToWait)
. If the
semaphore evaluates to 0, the task will block for the time specified in
ticksToWait
. When a task is finished using the semaphore,
the function xSemaphoreGive(semaphoreName)
is called.