Co je mutex?

  • Mutex je složen ze slov Mutual Exclusion (vzájemně se vylučující).

  • Je to semafor, který zahrnuje zděděný mechnismus priority. Mutex může mít dvě hodnoty: 0 nebo 1.

  • Mutex funguje jako "jeden klíč", který se používá k ochraně dat (zdroje). Kdo chce se zdrojem manipulovat, musí si vzít klíč (mutex), potom muže manipulovat se zdrojem. Po ukončení manipulace klíč odevzdá.

  • Zabraňuje tomu, aby dvě nebo více úloh měnily nějaká data (zdroj) současně.
    Když má mutex hodnotu 1, je k dispozici, pokud má hodnotu 0, někdo mutex používá a funkce volání xSemaphoreTake(mutex,prodleva) se zablokuje.

Kdy nelze používat mutex

  • Uvnitř zpracování přeušení

    • Mutex má zděděný mechanismus priority, který má smysl jenom tehdy pokud je mutex vzat nebo odevzdán z úlohy, nikoli z přerušení.

    • V rámci obsluhy přerušení nemůžeme dopustit blokování, abychom čekali na nějaký zdoj, který je chráněn mutexem, až bude uvolněn

FreeRTOS API funkce pro mutexy

  • xSemaphoreCreateMutex()

  • xSemaphoreTake(mutex, prodleva)

  • xSemaphoreGive(mutex)

Příklad

Nastavíme dvě úlohy tak, aby nemohly přerušovat jedna druhou, když tisknou znaky na sériovou linku.

Nastavení FreeRTOSConfig.h

#define configTICK_RATE_HZ                      100000

#define configUSE_MUTEXES                       1

#define configUSE_TIME_SLICING                  1
CMakeLists.txt
add_executable(${ProjectName}
    main.c
)

pico_enable_stdio_usb(${ProjectName} 1)
pico_enable_stdio_uart(${ProjectName} 0)

target_include_directories(${ProjectName} PRIVATE
    ${CMAKE_CURRENT_LIST_DIR}
)

target_link_libraries(${ProjectName}
    pico_stdlib
    FreeRTOS-Kernel-Heap4
    )

pico_add_extra_outputs(${ProjectName})

Kód bez mutexů

#include <FreeRTOS.h>
#include <task.h>
#include <stdio.h>
#include "pico/stdlib.h"


void task1(void *pvParameters)
{
    char ch = '1';
    while (true) {
        for(int i = 1; i < 10; i++){
            putchar(ch);
        }
        puts("");
    }
}

void task2(void *pvParameters)
{
    char ch = '2';
    while (true) {
        for(int i = 1; i < 10; i++){
            putchar(ch);
        }
        puts("");
    }
}


int main()
{
    stdio_init_all();

    xTaskCreate(task1, "Task 1", 256, NULL, 1, NULL);
    xTaskCreate(task2, "Task 2", 256, NULL, 1, NULL);
    vTaskStartScheduler();

    while(1){};
}

Kód s mutexy

#include <FreeRTOS.h>
#include <task.h>
#include <stdio.h>
#include "pico/stdlib.h"
#include "semphr.h" // zde jsou deklarace funkcí pro mutexy


// definice mutexu jako globální statické proměnné
static SemaphoreHandle_t mutex;

// definice prvního úkolu, bude tisknout na sériovou linku samé jedničky
void task1(void *pvParameters)
{
    char ch = '1';
    while (true) {
        if(xSemaphoreTake(mutex, 0) == pdTRUE){ // test získání mutexu, pokud ho nezískám funkce blokuje
            for(int i = 1; i < 10; i++){ // získal jsem mutex, mohu tisknout
                putchar(ch);
            }
            puts("");
            xSemaphoreGive(mutex); // odevzdání mutexu
        }

    }
}

// definice druhého úkolu, bude tisknout na sériovou linku samé dvojky
void task2(void *pvParameters)
{
    char ch = '2';
    while (true) {
        if(xSemaphoreTake(mutex, 0) == pdTRUE){
            for(int i = 1; i < 10; i++){
                putchar(ch);
            }
            puts("");
            xSemaphoreGive(mutex);
        }

    }
}


int main()
{
    stdio_init_all();

    mutex = xSemaphoreCreateMutex();

    xTaskCreate(task1, "Task 1", 256, NULL, 1, NULL); // vytvoření prvního úkolu
    xTaskCreate(task2, "Task 2", 256, NULL, 1, NULL); // vytvoření druhého úkolu
    vTaskStartScheduler();  // spuštění obou úloh

    while(1){};
}

Zdroje a odkazy