Passing data between RTOS tasks
This is the first of an occasional series of blog postings where I will focus on a specific feature or functionality of real time operating systems [RTOS]. These postings tie in somewhat with my RTOS Revealed series of articles on embedded.com My perspective will be as a user of Mentor’s Nucleus RTOS, from where I may draw examples, but most of the information will be much more widely applicable.
To start off with, I am going to look at how data may be passed between tasks …
It is very common that one task has some data that needs to be sent to another task for processing. It might seem obvious to just place the data in a global variable [or array, structure or whatever], so that it is accessible to both tasks. Although this would work fine, some care would be needed with synchronization – you do not want the receiving task to read the data until the sending one has finished writing it. Such synchronization is quite possible, but, to make things easier, most RTOSes have built-in data transfer facilities, where all the synchronization is taken care of.
A very simple inter-task data transfer facility is a mailbox. This is a fixed size object – normally a single 32-bit word that is commonly used to pass a pointer.
If a mailbox is empty, a task can save some data into it. The mailbox is then marked as full. A further attempt to load data will result in an error or task suspension. Another task can read the data, which renders the mailbox empty. An attempt to read from an empty mailbox results in an error or task suspension.
Sometimes the generation and consumption of data may be occurring at different rates. In this case, a buffer, that can hold multiple data items, between the tasks makes sense. Such a buffer is normally “first in, first out” [FIFO] and we call it a queue. It is typically implemented as a ring buffer, but, to use it, this information is not needed. It is just a matter of putting data in one end and extracting it from the other.
One task can place data in the queue repeatedly until the queue is full. The example here can take four objects. Further attempts to place data will result in an error or task suspend. Another task can repeatedly remove data items from the queue and will receive them in the same order that the first task send them. An attempt to read from an empty queue results in an error or a task suspend.
If data of more arbitrary size is to be transferred, an alternative facility may be available, which is commonly called a pipe. A pipe takes messages of arbitrary size; they may be a fixed or variable size – this will typically be determined when the pipe is created.
Some other RTOS facilities are associated with synchronization and data transfer between tasks: semaphores, event flags and partition memory. I will talk about these in future posts.