
멀티태스킹 환경에서 여러 Tasks가 동시에 하나의 자원에 접근하면 예기치 못한 동작이 발생할 수 있다. 예를 들어, 두 개의 Tasks가 동시에 시리얼 포트에 메시지를 출력한다면 문자열이 서로 뒤섞여 출력될 것이다. 이를 방지하기 위해 Mutual Exclusion이 사용된다. 보통 Mutex라고 불린다.
정리하면 Mutex은 여러 Tasks가 동시에 공유 자원에 접근하지 못하도록 한번에 하나의 Task만 접근 가능하게 보장하는 메커니즘이다. Binary Semaphore와 유사하지만, Mutex은 소유 개념(owner concept)이 존재하며, Mutex을 획득한 Tasks만 반환할 수 있다.
Mutex은 멀티태스킹 환경에서 데이터 무결성(Data Integrity)과 출력의 일관성을 지키기 위해 필수적이다.
예시:
Serial.println()을 호출하면 출력 문자열이 섞임① Mutex Handle 생성
Mutex을 생성하면 SemaphoreHandle_t 타입의 Handle이 반환된다. 이 Handle을 이용하여 Mutex을 획득(take)하거나 반환(give)할 수 있다.
SemaphoreHandle_t xMutex;
② setup() 함수
시리얼 통신을 초기화하고, Mutex을 생성한다. 이후 두 개의 Tasks을 생성한다. 각 Task는 동일한 함수(OutputTask)를 실행하지만, 다른 문자열을 매개변수로 전달받는다.
void setup()
{
Serial.begin(9600);
xMutex = xSemaphoreCreateMutex();
xTaskCreate(OutputTask,"Printer Task 1", 100,"Task 1 #####################Task1 \r\n",1,NULL);
xTaskCreate(OutputTask,"Printer Task 2", 100,"Task 2 ---------------------Task2 \r\n",2,NULL);
}
③ Task 함수
각 Task는 전달받은 문자열을 무한 반복으로 출력한다. 출력 시에는 반드시 printer() 함수를 통해 Mutex을 사용한다.
void OutputTask(void *pvParameters)
{
char *pcStringToPrint;
pcStringToPrint = (char *)pvParameters;
while(1)
{
printer(pcStringToPrint);
vTaskDelay(pdMS_TO_TICKS(100));
}
}
④ printer() 함수
Mutex을 사용하여 Serial.println()을 보호한다. xSemaphoreTake()로 Mutex을 얻은 후 출력하고, xSemaphoreGive()로 반환한다.
void printer(const char* pcString)
{
xSemaphoreTake(xMutex, portMAX_DELAY);
Serial.println(pcString);
xSemaphoreGive(xMutex);
}
⑤ 전체 코드
#include <Arduino_FreeRTOS.h>
#include "semphr.h"
SemaphoreHandle_t xMutex;
void setup()
{
Serial.begin(9600);
xMutex = xSemaphoreCreateMutex();
xTaskCreate(OutputTask,"Printer Task 1", 100,"Task 1 #####################Task1 \r\n",1,NULL);
xTaskCreate(OutputTask,"Printer Task 2", 100,"Task 2 ---------------------Task2 \r\n",2,NULL);
}
void OutputTask(void *pvParameters)
{
char *pcStringToPrint;
pcStringToPrint = (char *)pvParameters;
while(1)
{
printer(pcStringToPrint);
vTaskDelay(pdMS_TO_TICKS(100));
}
}
void printer(const char* pcString)
{
xSemaphoreTake(xMutex, portMAX_DELAY);
Serial.println(pcString);
xSemaphoreGive(xMutex);
}
void loop(){}