A mutex is a structure that can be used to serialize resource access. Tasks can lock and unlock mutexes. Each mutex has a lock count that enables a task to recursively lock the mutex. Tasks must ensure that the number of unlocks matches the number of locks. When a mutex has already been locked by another task, a task that wants to lock it must wait until the mutex becomes unlocked. The task that locks a mutex is assigned a higher priority than any other tasks waiting to lock that mutex; this avoids what is often called priority inversion, which can prevent some tasks from ever getting access to a required resource. Mutexes cannot be used by interrupt service routines.
You allocate a mutex by declaring it as a C variable. For example:
CTL_MUTEX_t mutex;
A mutex must be intitialized before any task can use it. To initialize a mutex, use ctl_mutex_init as in this example:
ctl_mutex_init(&mutex);
You can lock a mutex with an optional timeout by using ctl_mutex_lock:
ctl_mutex_lock(&mutex, CTL_TIMEOUT_NONE, 0);
You can unlock a mutex by using ctl_mutex_unlock:
ctl_mutex_unlock(&mutex);
Note: Only the locking task must unlock a successfully-locked mutex.
The following example illustrates resource serialization of two tasks.
CTL_MUTEX_t mutex;
void fn1(void)
{
ctl_lock_mutex(&mutex, CTL_TIMEOUT_NONE, 0);
⁞
ctl_unlock_mutex(&mutex);
}
void fn2(void)
{
ctl_lock_mutex(&mutex, CTL_TIMEOUT_NONE, 0);
⁞
fn1();
⁞
ctl_unlock_mutex(&mutex);
}
void task1(void)
{
for (;;)
{
fn2()
}
}
void task2(void)
{
for (;;)
{
fn1();
}
}
int main(void)
{
⁞
ctl_mutex_init(&mutex);
⁞
}Note that task1 locks the mutex twice by calling fn2 which then calls fn1.