The following RTOS mechanisms can be used to protect shared data resources. They are listed in a decreasing order of severity as regarding system latency (all pend and post functions are at the same level).
OSSemPend() OSSemPost() | Protects an area of memory or resource. A task calls OSSemPend, which will block until the resource is available. OSSemPost releases the resource. |
OSMboxPend() OSMboxPost() | Same as semaphore, except a pointer variable is passed as the “message”. A task or ISR can post a message, but only a task can pend on a message. Both the posting task and pending task must agree on what the pointer points to. |
OSQPend() OSQPost() | A Queue is basically an array of mailboxes. It is used to post one or more messages. When you initialize a Queue, you must specify the maximum number of messages. The first message posted to the queue will be the first message extracted from the queue (FIFO). |
OSFifoPend() OSFifoPost() OSFifoPostFirst() OSFifoPendNoWait() | A FIFO is similar to a queue, but is specifically designed to pass pointers to OS_FIFO structures. The first parameter of the structure must be a (void *) element, which is used by the operating system to create a linked list of FIFOs. When initializing a FIFO, you do not specify the maximum number of entries as with a queue. Instead, your application has the ability (and responsibility) to allocate memory (static or dynamic) in which to store the structures. This can be done statically by declaring global variables, or dynamically by allocating memory from the heap. As with a queue, the first message posted to the FIFO will be the first message extracted from the queue. |
OSCritEnter OSCritExit OSCritObj | This is a counted critical section that restricts access to resources to one task at a time, sometimes called a “mutex”. For example, you have a linked list that is maintained by 3 separate tasks. If one task is manipulating the list, you could first call OSCirtEnter for that object (the list). If any other task tries to manipulate the list, it will block at the OSCritEnter until the task that previously called OSCritEnter, calls OSCritExit. Note that the number of enter calls must match number of exit calls. OSCritObj is a C++ implementation that uses scoping to automatically call the enter and exit functions. See example below. |
OSLock() OSUnlock() OSLockObj | Disables other tasks, but not interrupts. Increments for each OSLock, decrements for each OSUnlock. The C++ object OSLockObj was created to assist in making sure that an unlock is called for each lock. When an OSLockObj is created, the constructor calls OSLock( ). When the object goes out of scope, OSUnlock( ) is automatically called by the destructor. |
USER_ENTER_CRITICAL() USER_EXIT_CRITICAL() | Macro that disables other tasks and interrupts. Increments count on enter, decrements on exit. |
How do you decide which type of mechanism to use? Some guidelines are: