Mutex or Semaphore

I understood if we want to protect resource we can use mutex or Semaphore I have gone through documents avillable for freertos but I don’t understand what ( mutex or Semaphore ) to use in which situation ?

I have written and tested code for mutex or Semaphore I think both looks same the only difference is in coding style.

ESP32, arduino IDE

Mutex

/* Include FreeRTOS APIs and defines */
#include <mutex>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/timers.h"


SemaphoreHandle_t mutex = xSemaphoreCreateMutex();

const int RED = 4;

void setup()
{
   assert(mutex);
   Serial.begin(115200);
 
   pinMode(RED, OUTPUT);
   
  xTaskCreatePinnedToCore(Task1, "Task1", 1000, NULL, 1, NULL, 0);    
  xTaskCreatePinnedToCore(Task2, "Task2", 1000, NULL, 1, NULL, 0);  
 
}   

void Task1( void * parameter )
{
 
  for(;;)
  {
     xSemaphoreTake(mutex, portMAX_DELAY);
     digitalWrite( RED, HIGH);
     vTaskDelay( 400 );
     digitalWrite( RED, LOW);
     vTaskDelay( 400 );
     xSemaphoreGive(mutex);
  }
}

void Task2( void * parameter )
{
  for(;;)
  {
    xSemaphoreTake(mutex, portMAX_DELAY);
    digitalWrite(RED, HIGH);
    vTaskDelay( 500 );
    digitalWrite(RED, LOW);
    vTaskDelay( 500 );
    xSemaphoreGive(mutex);
  }
}

void loop() {}

Semaphore

/* Include FreeRTOS APIs and defines */
#include <mutex>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/timers.h"


SemaphoreHandle_t mutex = xSemaphoreCreateMutex();

const int RED = 4;

void setup()
{
   assert(mutex);
   Serial.begin(115200);
 
   pinMode(RED, OUTPUT);
   
  xTaskCreatePinnedToCore(Task1, "Task1", 1000, NULL, 1, NULL, 0);    
  xTaskCreatePinnedToCore(Task2, "Task2", 1000, NULL, 1, NULL, 0);  
 
}   

void Task1( void * parameter )
{
 
  for(;;)
  {
     xSemaphoreTake(mutex, portMAX_DELAY);
     digitalWrite( RED, HIGH);
     vTaskDelay( 400 );
     digitalWrite( RED, LOW);
     vTaskDelay( 400 );
     xSemaphoreGive(mutex);
  }
}

void Task2( void * parameter )
{
  for(;;)
  {
    xSemaphoreTake(mutex, portMAX_DELAY);
    digitalWrite(RED, HIGH);
    vTaskDelay( 500 );
    digitalWrite(RED, LOW);
    vTaskDelay( 500 );
    xSemaphoreGive(mutex);
  }
}

void loop() {}

Can anyone give me situation where it can be figured out weather to use mutex or Semaphore

The code in both examples IS identical :wink:

SemaphoreHandle_t mutex = xSemaphoreCreateMutex();

Typo ?

However, the main and important difference between a FreeRTOS (binary) semaphore and a mutex is that a mutex supports priority inheritance (up to a certain degree).
This usually applies to other implementations/OS, too.
Besides the different semantics. It’s more than just coding style :wink:
If one reads ‘mutex’ she knows that the author protects something.
When reading ‘semaphore’ he assumes that the author signals something.

In my mind it is a bit like comparing a Swiss Army Knife (the Semaphore) and a scalpel (the Mutex). You can use the semaphore when you really want a Mutex, but it doesn’t work as well.

When protecting a resource, the only access pattern that really makes sense is Take, Use, Release/Give (by the task that took), and the Mutex ugly supports that pattern, while a Semaphore can be used in other patterns (like one tasks gives, and a second task takes, to synchronize them).

When you are using the Take, Use, Release, pattern, the Mutex provides a few enhancements the Semaphore can’t.

First, is priority inheritance, if a low priority task holds the Mutex, but gets interrupted by a Higher priority task, which then tries to take the Mutex, the low priority task will temporarily ‘inheret’ the high priority so a middle priority task can’t block the low priority task, and thus also block the high priority task. Semaphores don’t have logic to handle this, in part because Semaphores aren’t ‘owned’ by the task that takes them.

A second advantage is Mutexes can be made ‘Recursive’, so if the task that holds it takes it again, it can succeed, which Semaphores also can’t do.

1 Like

The only addition left to complement the very concise explanations of Hartmut and Richard is that Muteces track ownership. That is a prerequirement of their ability to support priority inheritance as well as the recursive variant, but not the same thing!

What that means in practice is that FreeRTOS will return an error if the task that releases a mutex is not the same task as the one that claimed it. With binary semaphores, the error will not happen, this is perfectly legit and desired as a semaphore (as was mentioned before) is a signal, not a traffic light. Also note that a semaphore can only be used similarly as a mutex if it is created as a binary semaphore which is initially untaken. Semaphores can be created and used in more generic ways.

1 Like