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.