Mutex and binary semaphore both help control access to shared resources in FreeRTOS. They prevent problems when multiple tasks try to use the same thing at the same time.
Mutex vs binary semaphore difference in FreeRTOS
/* Mutex creation */ SemaphoreHandle_t xMutex = xSemaphoreCreateMutex(); /* Binary semaphore creation */ SemaphoreHandle_t xBinarySemaphore = xSemaphoreCreateBinary();
Mutexes have ownership: only the task that locks it can unlock it.
Binary semaphores do not have ownership and can be given from an interrupt or another task.
/* Using a mutex */ if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) { // Access shared resource xSemaphoreGive(xMutex); }
/* Using a binary semaphore for signaling */ // Task waits for semaphore xSemaphoreTake(xBinarySemaphore, portMAX_DELAY); // Interrupt or another task gives semaphore xSemaphoreGiveFromISR(xBinarySemaphore, NULL);
This program creates a mutex and a binary semaphore. One task uses the mutex to protect a resource. Another task waits for the binary semaphore, which is given from a simulated interrupt.
/* Simple FreeRTOS example showing mutex vs binary semaphore usage */ #include "FreeRTOS.h" #include "task.h" #include "semphr.h" #include <stdio.h> SemaphoreHandle_t xMutex; SemaphoreHandle_t xBinarySemaphore; void vTaskUsingMutex(void *pvParameters) { if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) { printf("Mutex taken by task\n"); // Simulate resource use vTaskDelay(pdMS_TO_TICKS(100)); xSemaphoreGive(xMutex); printf("Mutex given back by task\n"); } vTaskDelete(NULL); } void vTaskWaitingForSemaphore(void *pvParameters) { printf("Task waiting for binary semaphore\n"); if (xSemaphoreTake(xBinarySemaphore, portMAX_DELAY) == pdTRUE) { printf("Binary semaphore received by task\n"); } vTaskDelete(NULL); } void vSimulateISR(void *pvParameters) { vTaskDelay(pdMS_TO_TICKS(500)); BaseType_t xHigherPriorityTaskWoken = pdFALSE; xSemaphoreGiveFromISR(xBinarySemaphore, &xHigherPriorityTaskWoken); printf("Binary semaphore given from ISR\n"); vTaskDelete(NULL); } int main(void) { xMutex = xSemaphoreCreateMutex(); xBinarySemaphore = xSemaphoreCreateBinary(); xTaskCreate(vTaskUsingMutex, "MutexTask", 1000, NULL, 1, NULL); xTaskCreate(vTaskWaitingForSemaphore, "SemTask", 1000, NULL, 1, NULL); xTaskCreate(vSimulateISR, "ISRSim", 1000, NULL, 1, NULL); vTaskStartScheduler(); for(;;); return 0; }
Mutexes support priority inheritance to avoid priority inversion problems.
Binary semaphores can be given from interrupts, mutexes cannot.
Use mutexes when you need ownership and priority handling, binary semaphores for simple signaling.
Mutexes are for exclusive access with ownership and priority inheritance.
Binary semaphores are simple flags for signaling without ownership.
Choose mutex or binary semaphore based on whether you need ownership and priority features.
Practice
mutex and a binary semaphore in FreeRTOS?Solution
Step 1: Understand ownership concept
Mutexes have ownership, meaning the task that locks it must unlock it. Binary semaphores do not have ownership.Step 2: Understand priority inheritance
Mutexes support priority inheritance to avoid priority inversion; binary semaphores do not.Final Answer:
Mutexes have ownership and priority inheritance; binary semaphores do not. -> Option BQuick Check:
Ownership + priority inheritance = Mutex [OK]
- Thinking binary semaphores have ownership
- Confusing signaling role of binary semaphores
- Assuming mutexes do not support priority inheritance
Solution
Step 1: Recall FreeRTOS API for mutex creation
The function to create a mutex isxSemaphoreCreateMutex().Step 2: Verify other options
xSemaphoreCreateBinary()creates a binary semaphore, not a mutex. The other options are invalid API calls.Final Answer:
xSemaphoreCreateMutex() -> Option AQuick Check:
Mutex creation function = xSemaphoreCreateMutex() [OK]
- Using xSemaphoreCreateBinary() for mutex
- Confusing queue creation functions with mutex
- Inventing non-existent API functions
SemaphoreHandle_t xMutex = xSemaphoreCreateMutex();
if (xSemaphoreTake(xMutex, 0) == pdTRUE) {
// Critical section
xSemaphoreGive(xMutex);
printf("Mutex taken and released\n");
} else {
printf("Failed to take mutex\n");
}
What will be the output when this code runs?Solution
Step 1: Analyze mutex creation and take
The mutex is created successfully. The call toxSemaphoreTakewith zero block time tries to take the mutex immediately. Since it is free, it succeeds.Step 2: Check critical section and release
The mutex is given back withxSemaphoreGive, and the message "Mutex taken and released" is printed.Final Answer:
Mutex taken and released -> Option AQuick Check:
Mutex free at start, take succeeds, prints message [OK]
- Assuming take fails with zero block time
- Confusing mutex with binary semaphore behavior
- Expecting compilation errors from correct API usage
SemaphoreHandle_t xBinarySemaphore = xSemaphoreCreateBinary();
xSemaphoreGive(xBinarySemaphore);
if (xSemaphoreTake(xBinarySemaphore, portMAX_DELAY) == pdTRUE) {
// Critical section
xSemaphoreGive(xBinarySemaphore);
xSemaphoreGive(xBinarySemaphore);
}Solution
Step 1: Understand binary semaphore usage
Binary semaphores act like flags with max count 1. Giving twice without taking in between can cause logic errors.Step 2: Analyze the code's semaphore give calls
The code gives the semaphore twice without an intervening take, which can lead to unexpected behavior or overflow.Final Answer:
Giving the semaphore twice causes incorrect behavior. -> Option DQuick Check:
Binary semaphore max count = 1, double give is wrong [OK]
- Thinking portMAX_DELAY is invalid
- Confusing binary semaphore with mutex creation
- Ignoring semaphore initialization
Solution
Step 1: Identify need for exclusive access with priority handling
Both tasks need exclusive access, so synchronization is required. Priority inversion can occur if a low priority task holds the resource.Step 2: Choose synchronization with priority inheritance
Mutexes provide priority inheritance, temporarily boosting the low priority task's priority to avoid blocking the high priority task.Final Answer:
Use a mutex because it supports priority inheritance. -> Option CQuick Check:
Priority inversion avoidance = mutex [OK]
- Choosing binary semaphore ignoring priority inversion
- Using counting semaphore for exclusive access
- Skipping synchronization to save time
Ready to prove it?
Pass the test and this pattern moves unknown
