본문 바로가기
임베디드 관련/FreeRTOS

[FreeRTOS] 이진 세마포어, 뮤텍스 사용법 및 비교

by minhyeok.lee 2024. 9. 14.
반응형

세마포어(Semaphore)와 뮤텍스(Mutex)

1. FreeRTOS에서 여러 태스크 간의 동기화와 공유 자원 보호를 위한 주요 동기화 도구이다.

2. 이 두 개념은 태스크들이 동시에 접근할 수 없는 공유 자원(예: 하드웨어, 변수)을 안전하게 사용할 수 있도록 제어한다.

3. 세마포어는 태스크 간의 동기화를 제공하고, 다수의 태스크가 자원에 접근할 수 있는지를 관리한다.

4. 뮤텍스는 상호 배제를 통해 한 번에 하나의 태스크만 특정 자원에 접근할 수 있도록 한다.


1. 세마포어(Semaphore)

1. 세마포어는 특정 자원을 여러 태스크가 동시에 사용하지 못하도록 제어하는 데 사용된다.

2. FreeRTOS에서 세마포어는 주로 이진(Binary) 세마포어와 카운팅(Counting) 세마포어로 나뉜다.

 

1.1. 이진 세마포어(Binary Semaphore)

1. 이진 세마포어는 두 가지 상태만 가진다.

2. 가용(Available) 또는 사용 중(Taken). 이진 세마포어는 0 또는 1의 값을 가지고 있으며, 자원이 사용 중이면 다른 태스크가 그 자원을 사용할 수 없도록 제어한다.

3. xSemaphoreGive(): 세마포어를 사용 가능한 상태로 변경한다.

4. xSemaphoreTake(): 세마포어가 사용 가능한 상태일 경우, 자원을 차지하고 세마포어를 '사용 중' 상태로 바꾼다.

 

이진 세마포어 예제

한 태스크가 세마포어를 사용하여 공유 자원에 접근하고, 다른 태스크는 그 자원이 사용 중일 때 대기하도록 한다.

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "Arduino.h"

SemaphoreHandle_t xSemaphore = NULL;

// 태스크 1: 공유 자원 사용
void task1(void *pvParameters) {
  while (true) {
    // 세마포어를 획득하려고 시도
    if (xSemaphoreTake(xSemaphore, portMAX_DELAY) == pdTRUE) {
      Serial.println("Task 1: Accessing shared resource");
      delay(1000);  // 공유 자원 사용 중 (1초 동안)

      // 세마포어 해제 (다른 태스크가 자원에 접근할 수 있도록 함)
      xSemaphoreGive(xSemaphore);
      Serial.println("Task 1: Released shared resource");
    }

    // 태스크가 잠시 대기 (다른 태스크 실행을 허용)
    vTaskDelay(pdMS_TO_TICKS(1000));
  }
}

// 태스크 2: 공유 자원 사용
void task2(void *pvParameters) {
  while (true) {
    // 세마포어를 획득하려고 시도
    if (xSemaphoreTake(xSemaphore, portMAX_DELAY) == pdTRUE) {
      Serial.println("Task 2: Accessing shared resource");
      delay(1000);  // 공유 자원 사용 중 (1초 동안)

      // 세마포어 해제 (다른 태스크가 자원에 접근할 수 있도록 함)
      xSemaphoreGive(xSemaphore);
      Serial.println("Task 2: Released shared resource");
    }

    // 태스크가 잠시 대기 (다른 태스크 실행을 허용)
    vTaskDelay(pdMS_TO_TICKS(1000));
  }
}

void setup() {
  Serial.begin(9600);

  // 이진 세마포어 생성
  xSemaphore = xSemaphoreCreateBinary();
  if (xSemaphore != NULL) {
    // 세마포어를 처음에는 사용 가능한 상태로 설정
    xSemaphoreGive(xSemaphore);

    // 두 태스크 생성
    xTaskCreate(task1, "Task 1", 1024, NULL, 1, NULL);
    xTaskCreate(task2, "Task 2", 1024, NULL, 1, NULL);
  }

  // FreeRTOS 스케줄러 시작
  vTaskStartScheduler();
}

void loop() {
  // FreeRTOS 스케줄러가 실행 중이므로 loop()는 비워 둠
}

 

1. xSemaphoreCreateBinary()로 이진 세마포어를 생성한다.

2. 태스크 1과 태스크 2는 각각 세마포어를 획득하려고 시도하며, 세마포어를 획득한 태스크만 공유 자원(여기서는 시리얼 출력)을 사용한다.

3. 자원 사용이 끝나면 xSemaphoreGive()로 세마포어를 반환하여, 다른 태스크가 자원을 사용할 수 있도록 한다.

 


2. 뮤텍스(Mutex)

1. 뮤텍스(Mutex)는 상호 배제(Mutual Exclusion)를 통해 단일 자원에 하나의 태스크만 접근하도록 보장한다.

2. 뮤텍스는 이진 세마포어와 비슷한 방식으로 작동하지만, 뮤텍스는 소유권 개념을 가지고 있다.

3. 즉, 뮤텍스를 획득한 태스크만 자원을 사용할 수 있으며, 해당 태스크가 자원을 반납해야만 다른 태스크가 그 자원을 사용할 수 있다.

 

뮤텍스 예제

태스크들이 뮤텍스를 사용하여 공유 자원을 보호하고, 한 번에 하나의 태스크만 자원을 사용할 수 있도록 한다.

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "Arduino.h"

SemaphoreHandle_t xMutex = NULL;

// 태스크 1: 뮤텍스를 사용하여 공유 자원 보호
void task1(void *pvParameters) {
  while (true) {
    // 뮤텍스 획득
    if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) {
      Serial.println("Task 1: Acquired mutex and using shared resource");
      delay(1000);  // 공유 자원 사용 중

      // 뮤텍스 해제
      xSemaphoreGive(xMutex);
      Serial.println("Task 1: Released mutex");
    }

    // 다른 태스크 실행을 허용하기 위한 대기 시간
    vTaskDelay(pdMS_TO_TICKS(1000));
  }
}

// 태스크 2: 뮤텍스를 사용하여 공유 자원 보호
void task2(void *pvParameters) {
  while (true) {
    // 뮤텍스 획득
    if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) {
      Serial.println("Task 2: Acquired mutex and using shared resource");
      delay(1000);  // 공유 자원 사용 중

      // 뮤텍스 해제
      xSemaphoreGive(xMutex);
      Serial.println("Task 2: Released mutex");
    }

    // 다른 태스크 실행을 허용하기 위한 대기 시간
    vTaskDelay(pdMS_TO_TICKS(1000));
  }
}

void setup() {
  Serial.begin(9600);

  // 뮤텍스 생성
  xMutex = xSemaphoreCreateMutex();
  if (xMutex != NULL) {
    // 두 태스크 생성
    xTaskCreate(task1, "Task 1", 1024, NULL, 1, NULL);
    xTaskCreate(task2, "Task 2", 1024, NULL, 1, NULL);
  }

  // FreeRTOS 스케줄러 시작
  vTaskStartScheduler();
}

void loop() {
  // FreeRTOS 스케줄러가 실행 중이므로 loop()는 비워 둠
}

1. xSemaphoreCreateMutex()로 뮤텍스를 생성한다.

2. 태스크 1과 태스크 2는 각각 뮤텍스를 사용하여 공유 자원에 접근하며, 한 번에 하나의 태스크만 자원을 사용할 수 있다.

3. 자원 사용이 끝나면 xSemaphoreGive()로 뮤텍스를 반환한다.

 

 


3. 세마포어와 뮤텍스의 차이점

특성 이진 세마포어 뮤텍스
주요 목적 태스크 간의 동기화 상호 배제를 통해 공유자원 보호
소유권 소유권 없음 소유권이 있으며, 뮤텍스를 획득한 태스크만 해제 가능
우선순위 상속 지원하지 않음 우선순위 상속(Priority Inheritance) 지원
사용 예 이벤트 신호나 플래그로 사용 공유 자원(예. 변수, 하드웨어) 보호

 

우선순위 상속: 뮤텍스는 우선순위 역전 문제를 해결하기 위해 우선순위 상속을 사용한다.

반응형

댓글