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.

Resource serialization with 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.