Mutual Exclusion

hyeony·2025년 8월 31일

RTOS

목록 보기
5/8

1. Mutual Exclusion

가. Introduction to Mutual Exclusion

1) What is Mutual Exclusion?

멀티태스킹 환경에서 여러 Tasks가 동시에 하나의 자원에 접근하면 예기치 못한 동작이 발생할 수 있다. 예를 들어, 두 개의 Tasks가 동시에 시리얼 포트에 메시지를 출력한다면 문자열이 서로 뒤섞여 출력될 것이다. 이를 방지하기 위해 Mutual Exclusion이 사용된다. 보통 Mutex라고 불린다.

정리하면 Mutex은 여러 Tasks가 동시에 공유 자원에 접근하지 못하도록 한번에 하나의 Task만 접근 가능하게 보장하는 메커니즘이다. Binary Semaphore와 유사하지만, Mutex소유 개념(owner concept)이 존재하며, Mutex을 획득한 Tasks만 반환할 수 있다.

2) Why do we need Mutex?

Mutex은 멀티태스킹 환경에서 데이터 무결성(Data Integrity)출력의 일관성을 지키기 위해 필수적이다.

예시:

  • 출력 장치 보호: 여러 Tasks가 동시에 Serial.println()을 호출하면 출력 문자열이 섞임
  • 센서 데이터 보호: 여러 Tasks가 동시에 센서 값을 읽거나 수정하면 데이터 충돌 발생
  • Actuator 제어: 하나의 모터를 여러 Tasks가 동시에 제어하면 오동작 발생

나. Code Implementation

① 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(){}

<참고 자료>
https://www.udemy.com/course/arduino-freertos/

profile
Chung-Ang Univ. EEE.

0개의 댓글