.. _sec-freertos-threadsynchronization:

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 TASK COMMUNICATION|.

In addition to the references provided in this guide, make sure to visit the 
|FreeRTOS API| for examples and detailed descriptions of FreeRTOS APIs. 

.. _sec-freertos-task-notifications:

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|
.

.. _sec-freertos-semaphores:

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".

.. _tbl-rtos-freertos-semaphore-translation:
.. table:: Semaphore translation table Other RTOS vs FreeRTOS

    +------------------+------------------+
    | Other RTOS       | FreeRTOS         |
    +------------------+------------------+
    | Semaphore_post() | xSemaphoreGive() |
    +------------------+------------------+
    | Semaphore_pend() | xSemaphoreTake() |
    +------------------+------------------+   

As shown above in :numref:`tbl-rtos-freertos-semaphore-translation`, 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:

    - |FreeRTOS BINARY SEMAPHORES|
    - |FreeRTOS COUNTING SEMAPHORES|

.. _sec-freertos-overview-event:

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|.
