Ở bài viết này mình sẽ hướng dẫn các bạn về Mutex. Mutex trong RTOS là gì, có bao nhiêu loại Mutex, nó được sử dụng và khởi tạo như thế nào? Các API của Mutex là những API nào và cách sử dụng nó ra sao ?
Mutex
Sử dụng cho việc loại trừ lẫn nhau(mutial exclution), nghĩa là nó được dùng để hạn chế quyền truy cập tới một số resource, mutex hoạt động như là một token để bảo vệ share resource, về cách hoạt động này khá giống với lại semaphore
Một task nếu muốn access vào share resource thì:
- Cần acquire (đợi) mutex trước khi truy cập vào share resource.
- Release token khi kết thúc với resource.
Tại mỗi một thời điểm thì chỉ có 1 task duy nhất có được mutex. Khi task này có mutex thì những task khác cũng muốn mutex này đều sẽ bị block cho tới khi task hiện tại release mutex ra.
Về cơ bản thì Mutex giống như binary semaphore nhưng được sử dụng cho việc loại trừ lẫn nhau chứ không phải đồng bộ.
Ngoài ra thì nó bao gồm cơ chế thừa kế mức độ ưu tiên(Priority inheritance mechanism) để giảm thiểu vấn đề đảo ngược ưu tiên, cơ chế này có thể hiểu đơn giản qua ví dụ sau:
- Task A (low priority) yêu cầu mutex
- Task B (high priority) muốn yêu cầu cùng mutex trên.
- Mức độ ưu tiên của Task A sẽ được đưa tạm về Task B để cho phép Task A được thực thi
- Task A sẽ thả mutex ra, mức độ ưu tiên sẽ được khôi phục lại và cho phép Task B tiếp tục thực thi.
Tạo Mutex
Bước 1: Định nghĩa mutex bằng hàm
osMutexDef(myMutex01);
Bước 2: Tạo mutex bằng hàm
osMutexId (myMutex01Handle);
myMutex01Handle = osMutexCreate(osMutex(myMutex01);
Với
- myMutex01: Tên của mutex
Acquire và release mutex
Task có thể acquire/ wait mutex với hàm
osMutexWait(myMutex01, osWaitForever);
Trong đó
- myMutex01: tên của mutex
- osWaitForever: giá trị timeout, trường hợp ko có timeout thì bằng 0
Task có thể release mutex với hàm
osMutexRelease(myMutex01);
Trong đó
- myMutex01: tên của mutex
API của mutex
Feature | CMSIS RTOS API | FreeRTOS API |
---|---|---|
Create mutex | osMutexCreate | xSemaphoreCreateMutex |
Delete mutex | osMutexDelete | vQueueDelete |
Acquire mutex | osMutexWait | xSemaphoreTake |
Release mutex | osMutexRelease | xSemaphoreGive |
Create recursivemutex | osRecursiveMutexCreate | xSemaphoreCreateRecursiveMutex |
Acquire recursivemutex | osRecursiveMutexWait | xSemaphoreTakeRecursive |
Release recursivemutex | osRecursiveMutexRelease | xSemaphoreGiveRecursive |
Ví dụ
Trong ví dụ này ta sẽ tạo 2 task đều sử dụng hàm printf và mutex sẽ được dùng để tránh xung đột.
Mở CubeMX chỉnh cấu hình cho FreeRTOS
- Sử dụng CubeMX để tạo 2 task với cùng priority
- Cấu hình enable mutex trong config
- Tạo mutex với tên tương ứng
Sau khi gen code, quan sát ta sẽ thấy
Định nghĩa mutex handle
/* Private variables ---------------------------------------------------------*/
osThreadId Task1Handle;
osThreadId Task2Handle;
osMutexId myMutex01Handle;
Tạo mutex
/* Create the mutex(es) */
/* definition and creation of myMutex01 */
osMutexDef(myMutex01);
myMutex01Handle = osMutexCreate(osMutex(myMutex01));
Điều chỉnh chương trình trong file main.c để Task 1 và 2 sử dụng mutex
Task 1:
/* USER CODE END Header_StartTask1 */
void StartTask1(void const * argument)
{
/* USER CODE BEGIN 5 */
/* Infinite loop */
for(;;)
{
osDelay(2000);
osMutexWait(myMutex01Handle, 1000);
printf("Task 1 Print\n");
osMutexRelease(myMutex01Handle);
}
/* USER CODE END 5 */
}
Task 2:
/* USER CODE END Header_StartTask2 */
void StartTask2(void const * argument)
{
/* USER CODE BEGIN StartTask2 */
/* Infinite loop */
for(;;)
{
osDelay(2000);
osMutexWait(myMutex01Handle, 1000);
printf("Task 2 Print\n");
osMutexRelease(myMutex01Handle);
}
/* USER CODE END StartTask2 */
}
Kết quả
Hình minh họa hoạt động của ví dụ trên
Ví dụ 2: Chờ update nha các bạn 😀
Tạm kết
Vậy là ở bài viết này mình đã làm rõ về Mutex trong RTOS là gì, sơ lược về Mutex , cách tạo Mutex ? Các API của Mutex và cách sử dụng nó trong ví dụ về Mutex. Phần tiếp theo sẽ là Software Timer trong RTOS, mời các bạn lót dép ngồi chờ nhé 😀