Incorrect mutex behavior?
Posted: Tue Dec 24, 2019 3:15 pm
I'm trying to track down a potential concurrency issue in a large codebase (which I can't share) and I'm checking my assumptions on FreeRTOS mutexes and semaphores. I've identified what appears to be incorrect behavior in the mutex, at least according to the docs.
The FreeRTOS docs ( https://www.freertos.org/CreateMutex.html ) say:
Here's my test program:
And the output:
According to the docs, the "give" task should not be able to give the mutex because the "take" task is the owner, but it works fine. I ran this test for 8+ hours and it never failed.
Can someone help me understand what is happening here?
Thanks,
Jason
The FreeRTOS docs ( https://www.freertos.org/CreateMutex.html ) say:
Lots of other pages on the Internet say that the primary difference between a mutex and a binary semaphore is that a mutex must be released by the owning thread, and it CAN NOT be released by another thread. This is what I'm seeing that I think may be incorrect. It appears that I can xSemaphoreGive(mutex) from another task just fine, breaking this contract.The priority of a task that ‘takes’ a mutex will be temporarily raised if another task of higher priority attempts to obtain the same mutex. The task that owns the mutex ‘inherits’ the priority of the task attempting to ‘take’ the same mutex. This means the mutex must always be ‘given’ back – otherwise the higher priority task will never be able to obtain the mutex, and the lower priority task will never ‘disinherit’ the priority.
Here's my test program:
Code: Select all
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
static SemaphoreHandle_t sem;
static void take(void* pv) {
while (true) {
printf("take %d\n", xSemaphoreTake(sem, portMAX_DELAY) == pdTRUE);
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
static void give(void* pv) {
while (true) {
printf("give %d\n", xSemaphoreGive(sem) == pdTRUE);
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
void app_main() {
sem = xSemaphoreCreateMutex();
xTaskCreate(take, "take", 7 * 1024, NULL, tskIDLE_PRIORITY, NULL);
xTaskCreate(give, "give", 7 * 1024, NULL, tskIDLE_PRIORITY + 1, NULL);
}
Code: Select all
I (237) cpu_start: Starting scheduler on PRO CPU.
give 0
take 1
give 1
take 1
give 1
take 1
give 1
Can someone help me understand what is happening here?
Thanks,
Jason