Pipe:
-
- A message pipe is an inter-process task communication tool used for inserting, deleting messages between two given interconnected task or two sets of tasks.
- In a pipe there are no fixed numbers of bytes per message but there is an end-point. A pipe can therefore be inserted limited number of bytes and have a variable number of bytes per message between initial and final pointers.
- Pipes are unidirectional i.e. one thread or task inserts into it and the other one reads and deletes from it.
- The read method of a pipe has no knowledge of where the write started, the interacting tasks must therefore share start and end locations as the messages are inserted into the pipe.
Mailbox:
- A message mailbox, also called a message exchange, is typically a pointer-size variable. Through a service provided by the kernel, a task or an ISR can deposit a message (the pointer) into this mailbox.
- One or more tasks can receive messages through a service provided by the kernel.
- Both the sender and receiving task agree on what the pointer is actually pointing to.
- A waiting list is associated with each mailbox in case more than one task wants to receive messages through the mailbox. A task desiring a message from an empty mailbox is suspended and placed on the waiting list until a message is received
- Typically, the kernel allows the task waiting for a message to specify a timeout. If a message is not received before the timeout expires, the requesting task is made ready to run, and an error code (indicating that a timeout has occurred) is returned to it
- When a message is deposited into the mailbox, either the highest priority task waiting for the message is given the message (priority-based), or the first task to request a message is given the message (First-In First-Out, or FIFO).
Figure shows a task depositing a message into a mailbox. Note that the mailbox is represented by an I-beam and the timeout is represented by an hourglass. The number next to the hourglass represents the number of clock ticks the task will wait for a message to arrive.
Message queue:
- A message queue is used to send one or more messages to a task. A message queue is basically an array of mailboxes. Through a service provided by the kernel, a task or an ISR can deposit a message (the pointer) into a message queue.
- One or more tasks can receive messages through a service provided by the kernel. Both the sender and receiving task or tasks have to agree as to what the pointer is actually pointing to.
- The first message inserted in the queue is the first message extracted from the queue (FIFO). In addition, to extract messages in a FIFO fashion, RTOSes allows a task to get messages Last-In-First-Out (LIFO).
- A waiting list is associated with each message queue, in case more than one task is to receive messages through the queue.
- The kernel allows the task waiting for a message to specify a timeout. If a message is not received before the timeout expires, the requesting task is made ready to run, and an error code (indicating a timeout has occurred) is returned to it.
- A task desiring a message from an empty queue is suspended and placed on the waiting list until a message is received.
- When a message is deposited into the queue, either the highest priority task, or the first task to wait for the message is given the message.
Figure shows an ISR depositing a message into a queue. Note that the queue is represented graphically by a double I-beam. The “10” indicates the number of messages that can accumulate in the queue. A “0” next to the hourglass indicates that the task will wait forever for a message to arrive.
Semaphore:
Semaphores are used to
a. control access to a shared resource (mutual exclusion)
b. signal the occurrence of an event
c. allow two tasks to synchronize their activities
A semaphore is a key that the program acquires in order to continue execution. If the semaphore is already in use, the requesting task is suspended until the semaphore is released by its current owner.
- Two types of semaphores exist: binary semaphores and counting semaphores. As its name implies, a binary semaphore can only take two values: 0 or 1. A counting semaphore allows values between 0 and 255, 65,535, depending on whether the semaphore mechanism is implemented using 8, 16, 32 bits. The actual size depends on the kernel used.
- Along with the semaphore’s value, the kernel also needs to keep track of tasks waiting for the semaphore’s availability.
- The initial value of the semaphore must be provided when the semaphore is initialized. The waiting list of tasks is always initially empty.
Generally, only three operations can be performed on a semaphore: INITIALIZE (also called CREATE), WAIT (also called PEND), and SIGNAL (also called POST).
a. WAIT: A task desiring the semaphore performs a WAIT operation. If the semaphore is available), the semaphore value is decremented, and the task continues execution else the task is placed in a waiting list. Most kernels allow a timeout to be specified; if the semaphore is not available within a certain amount of time, the requesting task is made ready to run, and an error code is returned.
b. SIGNAL: A task releases a semaphore by performing a SIGNAL operation. If no task is waiting for the semaphore, the semaphore value is simply incremented. If any task is waiting for the semaphore, however, one of the tasks is made ready to run, and the semaphore value is not incremented; the key is given to one of the tasks waiting for it. Depending on the kernel, the task that receives the semaphore is either the highest priority task waiting for the semaphore or the first task that requested the semaphore (First In First Out, or FIFO).
- Using a semaphore to access shared data doesn’t affect interrupt latency. If an ISR or the current task makes a higher priority task ready to run while accessing shared data, the higher priority task executes immediately.
- Semaphores are especially useful when tasks share I/O devices