Mutexes help make sure only one task uses a shared resource at a time. This stops problems when tasks try to use the same thing together.
Why mutexes protect shared resources in FreeRTOS
SemaphoreHandle_t xMutex;
xMutex = xSemaphoreCreateMutex();
// To take the mutex before using resource
if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) {
// Access shared resource
xSemaphoreGive(xMutex); // Release mutex after use
}You create a mutex with xSemaphoreCreateMutex().
Use xSemaphoreTake() to lock and xSemaphoreGive() to unlock the mutex.
SemaphoreHandle_t xMutex = xSemaphoreCreateMutex();
void Task1(void *pvParameters) {
if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) {
// Use shared resource
xSemaphoreGive(xMutex);
}
}void Task2(void *pvParameters) {
if (xSemaphoreTake(xMutex, 100 / portTICK_PERIOD_MS) == pdTRUE) {
// Use shared resource
xSemaphoreGive(xMutex);
} else {
// Could not get mutex, handle error or retry
}
}This program creates two tasks. One adds 1 to a shared counter, the other subtracts 1. Both use a mutex to avoid changing the counter at the same time. The output shows the counter changing safely.
#include "FreeRTOS.h" #include "task.h" #include "semphr.h" #include <stdio.h> SemaphoreHandle_t xMutex; int sharedCounter = 0; void vTaskIncrement(void *pvParameters) { for (int i = 0; i < 5; i++) { if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) { sharedCounter++; printf("Task Increment: Counter = %d\n", sharedCounter); xSemaphoreGive(xMutex); } vTaskDelay(10 / portTICK_PERIOD_MS); } vTaskDelete(NULL); } void vTaskDecrement(void *pvParameters) { for (int i = 0; i < 5; i++) { if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) { sharedCounter--; printf("Task Decrement: Counter = %d\n", sharedCounter); xSemaphoreGive(xMutex); } vTaskDelay(10 / portTICK_PERIOD_MS); } vTaskDelete(NULL); } int main(void) { xMutex = xSemaphoreCreateMutex(); if (xMutex == NULL) { printf("Mutex creation failed!\n"); return 1; } xTaskCreate(vTaskIncrement, "Increment", 1000, NULL, 1, NULL); xTaskCreate(vTaskDecrement, "Decrement", 1000, NULL, 1, NULL); vTaskStartScheduler(); // Should never reach here for(;;); return 0; }
Always create the mutex before starting tasks that use it.
Never forget to give back the mutex after using the shared resource.
If a task cannot get the mutex, it can wait or handle the situation gracefully.
Mutexes let only one task use a shared resource at a time.
This prevents data errors and keeps your program stable.
Use xSemaphoreTake() and xSemaphoreGive() to lock and unlock the mutex.
Practice
Solution
Step 1: Understand what a shared resource is
A shared resource is something multiple tasks want to use, like a variable or hardware.Step 2: Understand mutex purpose in FreeRTOS
Mutexes ensure only one task uses the resource at a time to avoid conflicts or errors.Final Answer:
To allow only one task to access the resource at a time -> Option AQuick Check:
Mutex = single task access [OK]
- Thinking mutex speeds up all tasks
- Believing mutex locks resource forever
- Assuming mutex duplicates resources
Solution
Step 1: Identify the function to lock a mutex
In FreeRTOS, xSemaphoreTake() is used to take or lock a mutex.Step 2: Confirm other functions' purposes
xSemaphoreGive() releases the mutex, vTaskDelay() delays a task, and xQueueSend() sends data to a queue.Final Answer:
xSemaphoreTake() -> Option CQuick Check:
Lock mutex = xSemaphoreTake() [OK]
- Confusing xSemaphoreGive() as lock
- Using vTaskDelay() to lock mutex
- Mixing queue functions with mutex
Solution
Step 1: Understand shared resource risks without mutex
Without mutex, tasks can change the variable at the same time, causing data corruption.Step 2: Check FreeRTOS behavior without explicit locking
FreeRTOS does not automatically lock variables; tasks run concurrently unless synchronized.Final Answer:
Data corruption or unexpected behavior may occur -> Option AQuick Check:
No mutex = risk of data corruption [OK]
- Assuming FreeRTOS auto-locks variables
- Thinking tasks wait automatically
- Believing no issues happen without mutex
if(xSemaphoreTake(mutex, 0) == pdTRUE) {
sharedVar++;
}
// Missing xSemaphoreGive(mutex) here
Solution
Step 1: Check mutex take and give usage
The code takes the mutex but never calls xSemaphoreGive() to release it.Step 2: Understand consequences of not releasing mutex
Not releasing the mutex causes other tasks to wait forever, leading to deadlock.Final Answer:
The mutex is never released, causing a deadlock -> Option DQuick Check:
Missing give = deadlock risk [OK]
- Forgetting to release mutex
- Assuming increment fails without mutex
- Confusing order of take/give
Solution
Step 1: Understand mutex best practice for shared data
Mutex should be held only briefly to protect the critical section (variable update).Step 2: Evaluate options for safe and efficient updates
Taking and giving mutex immediately around update prevents blocking other tasks too long.Final Answer:
Take the mutex, update the variable quickly, then give the mutex immediately -> Option BQuick Check:
Short mutex hold = safe and efficient [OK]
- Holding mutex too long blocking tasks
- Never releasing mutex causing deadlock
- Ignoring mutex and risking data errors
Ready to prove it?
Pass the test and this pattern moves unknown
