• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Mutex
2
3
4## Basic Concepts
5
6A mutual exclusion (mutex) is a special binary semaphore used for exclusive access to shared resources.
7
8A mutex can be unlocked or locked. When a task holds a mutex, the mutex is locked and the task obtains the ownership of the mutex. When the task releases the mutex, the mutex is unlocked and the task loses the ownership of the mutex. When a task holds a mutex, other tasks cannot unlock or hold the mutex.
9
10In an environment where multiple tasks compete for shared resources, the mutex can protect the shared resources via exclusive access. In addition, the mutex can prevent semaphore priority inversion, which occurs when a low-priority task holds a semaphore but a high-priority task has to wait until the low-priority task releases it.
11
12
13## Working Principles
14
15In a multi-task environment, multiple tasks may access the same shared resources. However, certain shared resources are not shared, and can only be accessed exclusively by tasks. A mutex can be used to address this issue.
16
17When non-shared resources are accessed by a task, the mutex is locked. Other tasks will be blocked until the mutex is released by the task. The mutex allows only one task to access the shared resources at a time, ensuring integrity of operations on the shared resources.
18
19**Figure 1** Mutex working mechanism for a mini system
20![](figures/mutex-working-mechanism-for-mini-systems.png "mutex-working-mechanism-for-mini-systems")
21
22
23## Available APIs
24
25  **Table 1** APIs of the mutex module
26
27| Category| Description|
28| -------- | -------- |
29| Creating or deleting a mutex| **LOS_MuxCreate**: creates a mutex.<br>**LOS_MuxDelete**: eeletes a mutex.|
30| Requesting or releasing a mutex| **LOS_MuxPend**: requests a mutex.<br>**LOS_MuxPost**: releases a mutex.|
31
32
33## How to Develop
34
35The typical mutex development process is as follows:
36
371. Call **LOS_MuxCreate** to create a mutex.
38
392. Call **LOS_MuxPend** to request a mutex.
40   The following modes are available:
41
42   - Non-block mode: A task acquires the mutex if the requested mutex is not held by any task or the task holding the mutex is the same as the task requesting the mutex.
43   - Permanent block mode: A task acquires the mutex if the requested mutex is not occupied. If the mutex is occupied, the task will be blocked and the task with a highest priority in the ready queue will be executed. The blocked task can be unlocked and executed only when a mutex is acquired.
44   - Scheduled block mode: A task acquires the mutex if the requested mutex is not occupied. If the mutex is occupied, the task will be blocked and the task with the highest priority in the ready queue will be executed. The blocked task can be executed only when the mutex is released within the specified timeout period or when the specified timeout period expires.
45
463. Call **LOS_MuxPost** to release a mutex.
47   - If tasks are blocked by the specified mutex, the task with a higher priority will be unblocked when the mutex is released. The unblocked task changes to the Ready state and is scheduled.
48   - If no task is blocked by the specified mutex, the mutex is released successfully.
49
504. Call **LOS_MuxDelete** to delete a mutex.
51
52> **NOTE**
53> - Nested mutexes are supported. That is, if a task that attempts to apply for a mutex and the task that already holds the mutex are the same task, the application is considered successful, and the lock is released based on the number of application times.
54>
55> - Mutexes cannot be used in an interrupt handler.
56>
57> - The LiteOS-M kernel must ensure real-time task scheduling and avoid long-time task blocking. Therefore, a mutex must be released as soon as possible after use.
58>
59> - When a mutex is held by a task, the task priority cannot be changed by using APIs such as **LOS_TaskPriSet**.
60
61
62## Development Example
63
64
65### Example Description
66
67This example implements the following:
68
691. Create a mutex for the **ExampleMutex** task. Lock task scheduling, and create two tasks **ExampleMutexTask1** and **ExampleMutexTask2**. Enable **ExampleMutexTask2** to permanently wait until a mutex is acquired, and enter sleep for 10 ticks after successfully acquiring a mutest. Enable **ExampleMutexTask1** to apply for a mutex with a timeout period of 10 ticks and then wait permanently until obtaining a mutex. **ExampleMutexTask2** has a higher priority than **ExampleMutexTask1**. Then, unlock task scheduling.
70
712. **ExampleMutexTask2** (which has a higher priority) is scheduled and applies for a mutex. After acquiring the mutex, **ExampleMutexTask2** starts to sleep for 100 ticks. **ExampleMutexTask2** is suspended, and **ExampleMutexTask1** is woken up.
72
733. **ExampleMutexTask1** applies for the mutex with a timeout period of 10 ticks. Because the mutex is still held by **ExampleMutexTask2**, **ExampleMutexTask1** is suspended. After 10 ticks, **ExampleMutexTask1** is woken up and starts to wait permanently for a mutex. **ExampleMutexTask1** is suspended because the mutex is still held by **ExampleMutexTask2**.
74
754. After 100 ticks, **ExampleMutexTask2** is woken up and releases the mutex, and **ExampleMutexTask1** is woken up. **ExampleMutexTask1** acquires the mutex and is executed. After the task is complte, **ExampleMutexTask1** releases the mutex. At last, the mutex is deleted.
76
77
78### Sample Code
79
80The sample code is as follows:
81
82The sample code is compiled and verified in **./kernel/liteos_m/testsuites/src/osTest.c**. Call **ExampleMutex** in **TestTaskEntry**.
83
84
85```
86#include "los_mux.h"
87
88/* Mutex handle. */
89UINT32 g_testMux;
90
91VOID ExampleMutexTask1(VOID)
92{
93    UINT32 ret;
94
95    printf("task1 try to get  mutex, wait 10 ticks.\n");
96    /* Request a mutex. */
97    ret = LOS_MuxPend(g_testMux, 10);
98    if (ret == LOS_OK) {
99        printf("task1 get mutex g_testMux.\n");
100        /* Release the mutex. This branch is reserved for exceptions. */
101        LOS_MuxPost(g_testMux);
102        LOS_MuxDelete(g_testMux);
103        return;
104    }
105
106    if (ret == LOS_ERRNO_MUX_TIMEOUT ) {
107        printf("task1 timeout and try to get mutex, wait forever.\n");
108        /* Request a mutex. */
109        ret = LOS_MuxPend(g_testMux, LOS_WAIT_FOREVER);
110        if (ret == LOS_OK) {
111            printf("task1 wait forever, get mutex g_testMux.\n");
112            /* Release the mutex. */
113            LOS_MuxPost(g_testMux);
114            /* Delete the mutex. */
115            LOS_MuxDelete(g_testMux);
116            printf("task1 post and delete mutex g_testMux.\n");
117            return;
118        }
119    }
120
121    return;
122}
123
124VOID ExampleMutexTask2(VOID)
125{
126    printf("task2 try to get  mutex, wait forever.\n");
127    /* Request a mutex. */
128    (VOID)LOS_MuxPend(g_testMux, LOS_WAIT_FOREVER);
129    printf("task2 get mutex g_testMux and suspend 100 ticks.\n");
130
131    /* Enable the task to enter sleep mode for 100 ticks. */
132    LOS_TaskDelay(100);
133
134    printf("task2 resumed and post the g_testMux\n");
135    /* Release the mutex. */
136    LOS_MuxPost(g_testMux);
137    return;
138}
139
140UINT32 ExampleMutex(VOID)
141{
142    UINT32 ret;
143    TSK_INIT_PARAM_S task1 = { 0 };
144    TSK_INIT_PARAM_S task2 = { 0 };
145    UINT32 taskId01;
146    UINT32 taskId02;
147
148    /* Create a mutex. */
149    LOS_MuxCreate(&g_testMux);
150
151    /* Lock task scheduling. */
152    LOS_TaskLock();
153
154    /* Create task 1. */
155    task1.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleMutexTask1;
156    task1.pcName       = "MutexTsk1";
157    task1.uwStackSize  = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
158    task1.usTaskPrio   = 5;
159    ret = LOS_TaskCreate(&taskId01, &task1);
160    if (ret != LOS_OK) {
161        printf("task1 create failed.\n");
162        return LOS_NOK;
163    }
164
165    /* Create task 2. */
166    task2.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleMutexTask2;
167    task2.pcName       = "MutexTsk2";
168    task2.uwStackSize  = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
169    task2.usTaskPrio   = 4;
170    ret = LOS_TaskCreate(&taskId02, &task2);
171    if (ret != LOS_OK) {
172        printf("task2 create failed.\n");
173        return LOS_NOK;
174    }
175
176    /* Unlock task scheduling. */
177    LOS_TaskUnlock();
178
179    return LOS_OK;
180}
181```
182
183
184### Verification
185
186  The development is successful if the return result is as follows:
187
188```
189task2 try to get  mutex, wait forever.
190task2 get mutex g_testMux and suspend 100 ticks.
191task1 try to get  mutex, wait 10 ticks.
192task1 timeout and try to get mutex, wait forever.
193task2 resumed and post the g_testMux
194task1 wait forever, get mutex g_testMux.
195task1 post and delete mutex g_testMux.
196```
197