Thread Synchronization¶
The FreeRTOS kernel provides several modules for synchronizing tasks such as RTOS Task Notifications, Semaphores, Events, and Queues. The following sections discuss these common FreeRTOS primitives at a high level. For more detail, see the FreeRTOS Inter-task Communication Overview.
In addition to the references provided in this guide, make sure to visit the FreeRTOS API Reference for examples and detailed descriptions of FreeRTOS APIs.
RTOS Task Notifications¶
RTOS task notifications are lightweight events that are sent directly to a task, as opposed to being sent through a semaphore, event, or queue. Tasks can block on task notifications just as tasks can block on a semaphore. Each task has an array of task notification, where each element in the array can serve as a different event.
RTOS task notifications use less RAM and execute significantly faster than its counterparts (i.e. semaphore, events). Notifications can only be used when there is only one task that can be the recipient of the event.
For more information and examples, please refer to FreeRTOS Task Notifications .
Semaphores¶
Semaphores are commonly used for task synchronization and mutual exclusions throughout RTOS applications.
Semaphores can be FreeRTOS Binary Semaphores or FreeRTOS Counting Semaphores.
Binary semaphores can have only two states: available (count = 1) and unavailable (count = 0). Binary semaphores can be used to share a single resource between tasks or for a basic-signaling mechanism where the semaphore can be “given” multiple times. Binary semaphores do not keep track of the count; they track only whether the semaphore has been “taken”.
Counting semaphores keep track of the number of items pending to be processed. Tasks can keep track of resources or count events using counting semaphores. When a group of resources are shared between tasks, a task can “take” a resource by taking the semaphore associated with it. When the task is done using said resource, it will “give” it back, freeing the semaphore. The semaphore’s count value will increment each time it is “given”, and decrement each “take”.
Other RTOS |
FreeRTOS |
Semaphore_post() |
xSemaphoreGive() |
Semaphore_pend() |
xSemaphoreTake() |
As shown above in Table 1., most other RTOS’s use the terminology post and pend when semaphores are used. With FreeRTOS, give and take are used as alluded to above.
FreeRTOS semaphore API functions allow a block time, which indicates the maximum number of “ticks” that a task should enter the Blocked state when attempting to take a semaphore. Taking a semaphore is a blocking call. A task will become unblocked when a semaphore is given back.
Caution
Certain FreeRTOS APIs must not be used inside an interrupt service routine
(ISR). Make sure to use functions suffixed by FromISR()
when called in
an ISR. As an example, xSemaphoreGiveFromISR()
should be used inside an
ISR, not xSemaphoreGive()
.
The semaphore.c
POSIX FreeRTOS driver provides an interface to use the
FreeRTOS semaphores through the use of a few simple API calls. The
uart2_callback
example leverages this driver and is a good reference to see
how it may be used in an application.
For more information on semaphores in FreeRTOS, including examples, please refer to the following FreeRTOS documentation on:
Event Groups¶
Semaphores themselves provide rudimentary synchronization between threads. Semaphores allow tasks to wait in a blocked state for a single event to occur and typically unblock when the event occurs. If a task wishes to wait on more than one event, a separate semaphore must be created for each event, using up extra memory while adding additional complexity to a system.
Event groups are used to allow a task to wait in the blocked state for a combination of one or more events to occur. Event groups will also unblock all the tasks that were waiting for the same event. In addition, using Event Groups can result in a smaller memory footprint when compared to semaphores alone.
Each event group contains a set of event bits (or flags). Each event flag can be either 1 or 0. This allows the event group to be stored in a single variable. When an event has occurred, its corresponding bit flag will be set to 1.
In addition to waking up a system on particular events, event groups can also be used to sync threads with each other, using a synchronization point. In practice, a synchronization point is a place in code where a task pends waiting for other threads to be ready. When all threads are ready, each task will unblock and execute code after the synchronization point.
For more information on Event Groups in FreeRTOS, including examples, please refer to the following FreeRTOS documentation covering FreeRTOS Event Groups.