© Copyright 2003
RealTimePartner
All rights reserved
Last update 2016-01
Intertask Synchronization
In multi-tasking applications, all tasks except the task with lowest priority need to block, i.e. make an RTOS call that will block the task. The task will then after some time be unblocked either by an ISR, another task or the RTOS itself, depending on the blocking condition of the task. The tasks can be divided into two groups:
Why do you need Intertask Synchronization?
If an application only has one single task with maybe a few interrupts, task synchronization is not needed as there are no other tasks to synchronize and it also means that there is no need for an ISR to synchronize the task either, as the task will always be ready to execute.
But in a multi-tasking application with several tasks with different priorities and also a number of ISRs, then you need a way block and unblock the tasks.
Intertask Data Communication
Why do you need Intertask Data Communication?
In a single task application there will be no conflicts accessing data, but if the application also includes a number of ISRs or it is a multi-tasking application sharing data between several tasks and maybe some ISRs, this may cause a race situation, where you e.g. may have a buffer containing data and one task that is writing data to the buffer and another task that reads the data, and you do not want them to do this "at the same time". So each time a task wants to write or read data from the buffer it needs to have exclusive access to the buffer and no other task may access the buffer until the first task has finished using it.
Mechanisms for Intertask Synchronization
Intertask synchronization basically means that you use some kind of mechanism to unblock a task, i.e. make it ready to start to execute as soon as tasks with higher priority has finished their execution and are blocked. Different RTOS may have different or several mechanisms to handle this. The way a task should be synchronized by another task, an ISR or the RTOS itself should of course be specified in your design.
Events (or Event Flags)
Events are probably the easiest mechanism to use, but you must know exactly which task you would like send the events to, as events are part of a task. If you need to synchronize a task from several sources then events are very useful, as a task can wait for several events at the same time.
For more details read: Events
Semaphores
If you do not know which task you should synchronize, you can not use events. In this case semaphores is the best mechanism to use. If you just want the synchronized task to execute once, even if you have given the semaphore several times, then you can use a binary semaphore. But if you want the task to execute exactly the same number as you have given the semaphore, than you should use a counting semaphore.
For more details read: Semaphores
Message Queues, Pipes, Mailboxes
(All these three mechanisms work very similar)
If you need to both synchronize and deliver data to another task at the same time, you should use a queue.
For more details read:Queues
Signals (UNIX like signals)
A signal will force a task to execute its signal routine, a separate routine that belongs to the task and that is not executed during the task's normal execution. Signals are often used when for extraordinary situations in the application, e.g. when a task has caused an exception, to be able to in a controlled way delete a task or shut-down and maybe reset the system.
Mechanisms for Intertask Communication
Many times tasks need to be able to share data that should only be accessible by one task at a time, i.e. when one task wants to write or read data no other task should be able to do it until the task has finished doing that. This can solved in many ways depending on the circumstances. The solution you have to choose depends on how the data should be treated by the task that reads the data. Two simple examples will explain the different models.
Condition Variables
Conditional variables is a very sophisticated way of synchronizing, probably not used so often, but for some design problems it may be the perfect solution. To be able to use a condition variable it needs to be associated with a mutex semaphore. In principle you can have one or several tasks that wait for a variable to be set to a specific value. One example that can be easily solved with a conditional variable is when you have a data base containing some kind of data, and it is acceptable that many tasks read data at the same time, but when a task wants to write into the data base it needs exclusive access to the data base.