CMSIS-RTOS2: Mutex Management

| CMSIS-RTOS2 Version 2.1.1 Real-Time Operating System: API and RTX Reference Implementation

- Main Page
- Usage and Description
- Reference

All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
Data Structures | Macros | Typedefs | Functions
Mutex Management
CMSIS-RTOS2 API

Synchronize resource access using Mutual Exclusion (Mutex). More...

## Data Structures
struct | osMutexAttr_t
| Attributes structure for mutex. More...

## Macros
#define | osMutexRecursive 0x00000001U
| Recursive mutex. More...
#define | osMutexPrioInherit 0x00000002U
| Priority inherit protocol. More...
#define | osMutexRobust 0x00000008U
| Robust mutex. More...

## Typedefs
typedef void * | osMutexId_t

## Functions
osMutexId_t | osMutexNew (const osMutexAttr_t *attr)
| Create and Initialize a Mutex object. More...
const char * | osMutexGetName (osMutexId_t mutex_id)
| Get name of a Mutex object. More...
osStatus_t | osMutexAcquire (osMutexId_t mutex_id, uint32_t timeout)
| Acquire a Mutex or timeout if it is locked. More...
osStatus_t | osMutexRelease (osMutexId_t mutex_id)
| Release a Mutex that was acquired by osMutexAcquire. More...
osThreadId_t | osMutexGetOwner (osMutexId_t mutex_id)
| Get Thread which owns a Mutex object. More...
osStatus_t | osMutexDelete (osMutexId_t mutex_id)
| Delete a Mutex object. More...

## Description

Mutual exclusion (widely known as Mutex) is used in various operating systems for resource management. Many resources in a microcontroller device can be used repeatedly, but only by one thread at a time (for example communication channels, memory, and files). Mutexes are used to protect access to a shared resource. A mutex is created and then passed between the threads (they can acquire and release the mutex).

CMSIS-RTOS Mutex

A mutex is a special version of a semaphore. Like the semaphore, it is a container for tokens. But instead of being able to have multiple tokens, a mutex can only carry one (representing the resource). Thus, a mutex token is binary and bounded, i.e. it is either available, or blocked by a owning thread. The advantage of a mutex is that it introduces thread ownership. When a thread acquires a mutex and becomes its owner, subsequent mutex acquires from that thread will succeed immediately without any latency (if osMutexRecursive is specified). Thus, mutex acquires/releases can be nested.

CMSIS-RTOS Mutex States

Note
  Mutex management functions cannot be called from Interrupt Service Routines (ISR), unlike a binary semaphore that can be released from an ISR.
  Refer to Mutex Configuration for RTX5 configuration options.

## Data Structure Documentation

struct osMutexAttr_t

Data Fields
const char * | name | name of the mutex Pointer to a string with a human readable name of the event object. Default: NULL.
uint32_t | attr_bits | attribute bits The following predefined bit masks can be assigned to set options for a mutex object.
Bit Mask | Description
--- | ---
osMutexRecursive | Mutex is recursive.
osMutexPrioInherit | Priority inheritance protocol.
osMutexRobust | Robust mutex.
void * | cb_mem | memory for control block Pointer to a memory location for the mutex control block object. This can optionally be used for custom memory management systems. Default: NULL (uses kernel memory management).
uint32_t | cb_size | size of provided memory for control block The size of the memory block passed with cb_mem. Must be the size of a mutex control block object or larger.

## Macro Definition Documentation

#define osMutexRecursive 0x00000001U

Recursive flag in osMutexAttr_t.

The same thread can consume a mutex multiple times without locking itself. Each time the owning thread acquires the mutex the lock count is incremented. The mutex must be released multiple times as well until the lock count reaches zero. At reaching zero the mutex is actually released and can be acquired by other threads.

Note
  The maximum amount of recursive locks possible is implementation specific, i.e. the type size used for the lock count. If the maximum amount of recursive locks is depleted mutex acquire might fail.

Code Example

#include "cmsis_os2.h"
osMutexId_t mutex_id;
const osMutexAttr_t Thread_Mutex_attr = {
"myThreadMutex", // human readable mutex name
osMutexRecursive, // attr_bits
NULL, // memory for control block
NULL // size for control block
};
// must be called from a thread context
void UseMutexRecursively(int count) {
osStatus_t result = osMutexAcquire(mutex_id, osWaitForever); // lock count is incremented, might fail when lock count is depleted
if (result == osOK) {
if (count < 10) {
UseMutexRecursively(count + 1);
}
osMutexRelease(mutex_id); // lock count is decremented, actually releases the mutex on lock count zero
}
}

#define osMutexPrioInherit 0x00000002U

Priority inheritance flag in osMutexAttr_t.

A mutex using priority inheritance protocol transfers a waiting threads priority to the current mutex owner if the owners thread priority is lower. This assures that a low priority thread does not block a high priority thread.

Otherwise a low priority thread might hold a mutex but is not granted execution time due to another mid priority thread. Without priority inheritance the high priority thread waiting for the mutex would be blocked by the mid priority thread, called priority inversion.

Code Example

This example reveals a blocked high priority thread if osMutexPrioInherit is removed.

#include "cmsis_os2.h"
osMutexId_t mutex_id;
const osMutexAttr_t Thread_Mutex_attr = {
"myThreadMutex", // human readable mutex name
osMutexPrioInherit, // attr_bits
NULL, // memory for control block
NULL // size for control block
};
void HighPrioThread(void *argument) {
osDelay(1000); // wait 1s until start actual work
while(1) {
osMutexAcquire(mutex_id, osWaitForever); // try to acquire mutex
// do stuff
osMutexRelease(mutex_id);
}
}
void MidPrioThread(void *argument) {
osDelay(1000); // wait 1s until start actual work
while(1) {
// do non blocking stuff
}
}
void LowPrioThread(void *argument) {
while(1) {
osMutexAcquire(mutex_id, osWaitForever);
osDelay(5000); // block mutex for 5s
osMutexRelease(mutex_id);
osDelay(5000); // sleep for 5s
}
}

During the first second the high and mid priority threads are delayed. Thus the low priority thread can start its work, acquires the mutex and delays while holding it.

After the first second the high and mid priority threads become ready. Thus the high priority thread gets precedence and tries to acquire the mutex. Because the mutex is already owned by the low priority thread the high priority thread gets blocked.

Finally the mid priority thread gets executed and start doing a lot of non-blocking stuff, i.e. it does not call any blocking RTOS functionality.

Without osMutexPrioInherit we would stuck here forever. Even if the low priority thread gets ready after 5s. Due to its low priority the mid priority thread always gets precedence. The effect called priority inversion leads to the mid priority thread blocking the high priority thread indirectly.

Using osMutexPrioInherit as shown in the example code we get rid of this situation. Due to the priority inheritance protocol the low priority thread inherites the high priority while holding the mutex. Thus the low priority thread gets precedence over the mid priority thread until it release the mutex. On osMutexRelease the high priority thread get ready and is scheduled immediately.

#define osMutexRobust 0x00000008U

Robust flag in osMutexAttr_t.

Robust mutexes are automatically released if the owning thread is terminated (either by osThreadExit or osThreadTerminate). Non-robust mutexes are not released and the user must assure mutex release manually.

Code Example

This example reveals a blocked mutex if osMutexRobust is removed.

#include "cmsis_os2.h"
osMutexId_t mutex_id;
const osMutexAttr_t Thread_Mutex_attr = {
"myThreadMutex", // human readable mutex name
osMutexRobust, // attr_bits
NULL, // memory for control block
NULL // size for control block
};
void Thread(void *argument) {
osMutexAcquire(mutex_id, osWaitForever);
osThreadExit();
}

Due to osMutexRobust the mutex gets released automatically. A non-robust mutex would stay locked and cannot be released anymore.

## Typedef Documentation

osMutexId_t

Mutex ID identifies the mutex.

Returned by:

- osMutexNew

## Function Documentation

osMutexId_t osMutexNew | ( | const osMutexAttr_t * | attr | ) |

Parameters

  [in] | attr | mutex attributes; NULL: default values.

Returns
  mutex ID for reference by other functions or NULL in case of error.

The function osMutexNew creates and initializes a new mutex object and returns the pointer to the mutex object identifier or NULL in case of an error. It can be safely called before the RTOS is started (call to osKernelStart), but not before it is initialized (call to osKernelInitialize).

The parameter attr sets the mutex object attributes (refer to osMutexAttr_t). Default attributes will be used if set to NULL.

Note
  This function cannot be called from Interrupt Service Routines.

Code Example

#include "cmsis_os2.h"
osMutexId_t mutex_id;
const osMutexAttr_t Thread_Mutex_attr = {
"myThreadMutex", // human readable mutex name
osMutexRecursive | osMutexPrioInherit, // attr_bits
NULL, // memory for control block
NULL // size for control block
};
void CreateMutex (void) {
mutex_id = osMutexNew(&Thread_Mutex_attr);
if (mutex_id != NULL) {
// Mutex object created
}
}

*const char * osMutexGetName | ( | osMutexId_t | mutex_id | ) |

Parameters

  [in] | mutex_id | mutex ID obtained by osMutexNew.

Returns
  name as NULL terminated string.

The function osMutexGetName returns the pointer to the name string of the mutex identified by parameter mutex_id or NULL in case of an error.

Note
  This function cannot be called from Interrupt Service Routines.

osStatus_t osMutexAcquire | ( | osMutexId_t | mutex_id,
|  | uint32_t | timeout
| ) |  |

Parameters

  [in] | mutex_id | mutex ID obtained by osMutexNew.
  [in] | timeout | Timeout Value or 0 in case of no time-out.

Returns
  status code that indicates the execution status of the function.

The blocking function osMutexAcquire waits until a mutex object specified by parameter mutex_id becomes available. If no other thread has obtained the mutex, the function instantly returns and blocks the mutex object.

The parameter timeout specifies how long the system waits to acquire the mutex. While the system waits, the thread that is calling this function is put into the BLOCKED state. The parameter timeout can have the following values:

- when timeout is 0, the function returns instantly (i.e. try semantics).
- when timeout is set to osWaitForever the function will wait for an infinite time until the mutex becomes available (i.e. wait semantics).
- all other values specify a time in kernel ticks for a timeout (i.e. timed-wait semantics).

Possible osStatus_t return values:

- osOK: the mutex has been obtained.
- osErrorTimeout: the mutex could not be obtained in the given time.
- osErrorParameter: parameter mutex_id is NULL or invalid.
- osErrorResource: the mutex specified by parameter mutex_id is in an invalid mutex state or the mutex could not be obtained when no timeout was specified.
- osErrorISR: cannot be called from interrupt service routines.

Note
  This function cannot be called from Interrupt Service Routines.

Code Example

#include "cmsis_os2.h"
void WaitMutex (void) {
osMutexId_t mutex_id;
osStatus_t status;
mutex_id = osMutexNew(NULL);
if (mutex_id != NULL) {
status = osMutexAcquire(mutex_id, 0);
if (status != osOK) {
// handle failure code
}
}
}

osStatus_t osMutexRelease | ( | osMutexId_t | mutex_id | ) |

Parameters

  [in] | mutex_id | mutex ID obtained by osMutexNew.

Returns
  status code that indicates the execution status of the function.

The function osMutexRelease releases a mutex specified by parameter mutex_id. Other threads that currently wait for this mutex will be put into the READY state.

Possible osStatus_t return values:

- osOK: the mutex has been correctly released.
- osErrorParameter: parameter mutex_id is NULL or invalid.
- osErrorResource: the mutex specified by parameter mutex_id is in an invalid mutex state or the mutex was not obtained before/the current thread is not the owner of the mutex.
- osErrorISR: osMutexRelease cannot be called from interrupt service routines.

Note
  This function cannot be called from Interrupt Service Routines.

Code Example

#include "cmsis_os2.h"
osMutexId_t mutex_id; // Mutex id populated by the function osMutexNew()
void ReleaseMutex (osMutexId_t mutex_id) {
osStatus_t status;
if (mutex_id != NULL) {
status = osMutexRelease(mutex_id);
if (status != osOK) {
// handle failure code
}
}
}

osThreadId_t osMutexGetOwner | ( | osMutexId_t | mutex_id | ) |

Parameters

  [in] | mutex_id | mutex ID obtained by osMutexNew.

Returns
  thread ID of owner thread or NULL when mutex was not acquired.

The function osMutexGetOwner returns the thread ID of the thread that acquired a mutex specified by parameter mutex_id. In case of an error or if the mutex is not blocked by any thread, it returns NULL.

Note
  This function cannot be called from Interrupt Service Routines.

osStatus_t osMutexDelete | ( | osMutexId_t | mutex_id | ) |

Parameters

  [in] | mutex_id | mutex ID obtained by osMutexNew.

Returns
  status code that indicates the execution status of the function.

The function osMutexDelete deletes a mutex object specified by parameter mutex_id. It releases internal memory obtained for mutex handling. After this call, the mutex_id is no longer valid and cannot be used. The mutex may be created again using the function osMutexNew.

Possible osStatus_t return values:

- osOK: the mutex object has been deleted.
- osErrorParameter: parameter mutex_id is NULL or invalid.
- osErrorResource: the mutex specified by parameter mutex_id is in an invalid mutex state.
- osErrorISR: osMutexDelete cannot be called from interrupt service routines.

Note
  This function cannot be called from Interrupt Service Routines.

Code Example

#include "cmsis_os2.h"
osMutexId_t mutex_id; // Mutex id populated by the function osMutexNew()
void DeleteMutex (osMutexId_t mutex_id) {
osStatus_t status;
if (mutex_id != NULL) {
status = osMutexDelete(mutex_id);
if (status != osOK) {
// handle failure code
}
}
}