Mutexes are used to help prevent priority inversion. They work by temporarily raising the priority of the lower task holding the mutex to a higher priority so that it will run and release the mutex.
On uCOS priorities must be unique. Because of that each mutex has its own priority. Typically one higher then the highest one of the tasks that share the mutex.
It only bumps up the priority of a task if a higher priority task is waiting on the same mutex. The task’s priority reverts back when it calls Post on the mutex.
The process of temporarily increasing the priority of a task is often called priority boosting.
In this scenario there are three tasks, Task1, Task2, and Task3 with priorities 1, 2, and 3 respectively. Task1 and Task3 are sharing a function, use(), that is protected by a semaphore.
At first Task3 is running and acquires semaphore. Right after that Task1 is signaled and starts to run since it has higher priority than Task3. Task1 runs until it tries to acquire the semaphore but since Task3 has the semaphore Task1 will need to wait until Task3 releases it. That much is a given. It’s a shared resource and only one task at a time can use it. Everything is ok at this point.
But if Task2 is signaled it will preempt Task3 because it has a higher priority then Task3. Task3 is no longer running yet it still holds the semaphore that is blocking Task1.
Task1 is now completely blocked and it’s priority is essentially less Task2’s priority. Hence the name priority inversion. Task1 may be blocked indefinitely even though it has the highest priority. Mutexes are designed to help solve this problem.
A mutex is a binary semaphore that can detect the case where it is being held by lower priority task when a higher priority task needs to acquire it. When the higher priority task calls Pend, the mutex will boost the prority of the lower task that is holding it so that the lower task will run release the mutex. The priority boosting helps to ensure the lower task will not be preempt while it is hold a mutex needed by a higher priority task.
OS_EVENT *OSMutexCreate(INT8U prio, INT8U *perr);
OS_EVENT *OSMutexDel(OS_EVENT *pevent, INT8U opt, INT8U *perr);
void OSMutexPend(OS_EVENT *pevent, INT16U timeout, INT8U *perr);
INT8U OSMutexPost(OS_EVENT *pevent);
BOOLEAN OSMutexAccept(OS_EVENT *pevent, INT8U *perr);
INT8U OSMutexQuery(OS_EVENT *pevent, OS_MUTEX_DATA *p_mutex_data);