Semaphore and Mutex in FreeRTOS using Arduino

ArduinoArduino BoardsArduino IDEArduino Programming Language

Semaphore and Mutex are tools/mechanisms to bring about synchronization between tasks in FreeRTOS. Often, two tasks need to share a resource, or one task needs to tell another that it is idle/waiting. Semaphores and Mutex help here. In this article, we will look at the concepts of semaphore and mutex.

Semaphore

A semaphore is a synchronization mechanism between tasks. More specifically, it is a signalling mechanism. A task in the waiting state may receive a semaphore which tells it to do some work. Once the task has done that work, it will give the semaphore back. In practice, this is maintained by integers. There are two types of semaphores: Binary Semaphore and Counting Semaphore.

Binary Semaphore

This is similar to a queue of length 1. It can take only 0 and 1 as the integer values. Say there are two tasks: task A and task B. If task A needs to send some periodic communication to task B (say exchange of data), then it uses this binary semaphore to communicate. When data is available, it sets the semaphore value to 1 (task A ‘gives’ the semaphore here). Task B, which is continuously monitoring the semaphore, will read the data when the value is 1. It will then set the value of the queue back to 0 (task B, thus, ‘takes’ the semaphore), and wait again for data to be available. This way, synchronization is achieved between tasks A and B.

Counting Semaphore

In this case, there are no restrictions on the length of the queue. This is used for event management. Every time an event happens, an event handler ‘gives’ the semaphore by incrementing the count value. And every time a task processes the event, it indicates that it has ‘taken’ the semaphore by decrementing the count. The count at any given point of time shows the difference between the number of events that have happened and the number of events processed.

Mutex

A mutex (Mutual Exclusion) is a locking mechanism that prevents corruption of shared resources. Say you have an SD Card that is being accessed by multiple tasks. If multiple tasks access it simultaneously, there is a possibility of the corruption of the data within the SD Card (both may be writing to the same memory area, resulting in garbage).

In order to avoid such a condition, we use a Mutex. It is like a token. If a task has this token, only that task can access the particular resource. Other tasks have to wait till the token is released by that task. If you have multiple resources (like OLED screen, SD Card, Serial port, etc.) that need to be protected, you can use multiple tokens, one for each resource.

In practice, Mutex uses the same API functions as binary semaphores. The only difference is that Mutexes have priority inheritance. The FreeRTOS documentation describes this as −

“If a high priority task blocks while attempting to obtain a mutex (token) that is currently held by a lower priority task, then the priority of the task holding the token is temporarily raised to that of the blocking task. This mechanism is designed to ensure the higher priority task is kept in the blocked state for the shortest time possible, and in so doing minimise the 'priority inversion' that has already occurred.”

In order to see the practical implementation of semaphores and mutex, you can look at the following examples that come with the FreeRTOS library: Mutex, AnalogRead_DigitalRead, Interrupts.

raja
Published on 29-May-2021 12:54:46
Advertisements