FreeRTOS

FreeRTOS Semaphore와 Mutex 활용하기

임베디드 친구 2025. 1. 14. 08:34
반응형

FreeRTOS는 임베디드 시스템에서 널리 사용되는 실시간 운영 체제(RTOS)로, 태스크 간 동기화 및 리소스 보호를 위한 다양한 동기화 메커니즘을 제공합니다. 이 글에서는 Semaphore와 Mutex를 활용하는 방법과 주요 차이점, 함수 사용법, 그리고 실제 사용 사례와 예제를 통해 FreeRTOS(CMSIS v1)에서 동기화를 구현하는 방법을 알아보겠습니다.


1. Semaphore와 Mutex의 차이점

Semaphore

  • 용도: 주로 태스크 간 신호 전달 또는 리소스 접근 허용/제어에 사용됩니다.
  • 특징:
    • 카운팅 세마포어와 바이너리 세마포어로 나뉩니다.
    • 특정 리소스의 사용 가능 여부를 태스크 간에 관리합니다.
    • 태스크 간 신호 전달(Signal)이 주 목적입니다.

Mutex (Mutual Exclusion)

  • 용도: 리소스 보호에 특화되어 있습니다.
  • 특징:
    • 소유권(Ownership)을 가지며, 소유한 태스크만 Mutex를 해제할 수 있습니다.
    • 우선순위 역전(Priority Inversion)을 방지하기 위한 우선순위 상속(Priority Inheritance)을 지원합니다.
    • 리소스 보호(Resource Protection)가 주 목적입니다.

주요 차이점

구분 Semaphore Mutex
용도 태스크 간 신호 전달 리소스 보호
소유권 없음 있음
우선순위 역전 방지하지 않음 우선순위 상속으로 방지
타입 바이너리/카운팅 세마포어 바이너리 뮤텍스

2. osSemaphoreAcquire()osSemaphoreRelease() 함수 사용법

osSemaphoreAcquire

osStatus_t osSemaphoreAcquire(osSemaphoreId_t semaphore_id, uint32_t timeout);
  • 설명: 지정된 세마포어를 획득합니다.
  • 매개변수:
    • semaphore_id: 세마포어 식별자.
    • timeout: 대기 시간(밀리초 단위, osWaitForever 사용 가능).
  • 반환값:
    • osOK: 성공적으로 세마포어를 획득함.
    • osErrorTimeout: 지정된 시간 내에 세마포어를 획득하지 못함.

osSemaphoreRelease

osStatus_t osSemaphoreRelease(osSemaphoreId_t semaphore_id);
  • 설명: 세마포어를 반환합니다.
  • 매개변수:
    • semaphore_id: 세마포어 식별자.
  • 반환값:
    • osOK: 성공적으로 세마포어를 반환함.
    • osErrorResource: 세마포어가 이미 반환된 상태.

코드 예제

osSemaphoreId_t semaphore;

// 세마포어 생성
semaphore = osSemaphoreNew(1, 1, NULL);

// 세마포어 획득
if (osSemaphoreAcquire(semaphore, osWaitForever) == osOK) {
    // 임계 영역 코드

    // 세마포어 반환
    osSemaphoreRelease(semaphore);
}

3. 리소스 보호를 위한 Mutex 사용 사례

Mutex를 이용한 리소스 보호

Mutex는 여러 태스크가 동일한 리소스를 사용할 때 데이터 무결성을 보장하는 데 유용합니다. 예를 들어, 공유 메모리 접근 시 Mutex를 사용하여 태스크가 순차적으로 접근하도록 제어할 수 있습니다.

코드 예제

osMutexId_t mutex;

// Mutex 생성
mutex = osMutexNew(NULL);

void Task1(void *argument) {
    while (1) {
        // Mutex 획득
        if (osMutexAcquire(mutex, osWaitForever) == osOK) {
            // 공유 리소스 접근
            printf("Task1: Accessing shared resource\n");

            // Mutex 반환
            osMutexRelease(mutex);
        }
        osDelay(100);
    }
}

void Task2(void *argument) {
    while (1) {
        // Mutex 획득
        if (osMutexAcquire(mutex, osWaitForever) == osOK) {
            // 공유 리소스 접근
            printf("Task2: Accessing shared resource\n");

            // Mutex 반환
            osMutexRelease(mutex);
        }
        osDelay(150);
    }
}

4. 다중 태스크 간 동기화 예제

세마포어를 활용한 태스크 동기화

두 태스크 간에 세마포어를 사용하여 동기화를 구현할 수 있습니다. 아래 예제는 Task1에서 신호를 보낼 때 Task2가 해당 신호를 대기하고 동작을 수행하는 구조입니다.

코드 예제

osSemaphoreId_t semaphore;

void Task1(void *argument) {
    while (1) {
        // Task1에서 신호 전송
        osSemaphoreRelease(semaphore);
        printf("Task1: Semaphore released\n");
        osDelay(500);
    }
}

void Task2(void *argument) {
    while (1) {
        // Task2에서 신호 대기
        if (osSemaphoreAcquire(semaphore, osWaitForever) == osOK) {
            printf("Task2: Semaphore acquired\n");
        }
    }
}

int main(void) {
    // 세마포어 생성
    semaphore = osSemaphoreNew(1, 0, NULL);

    // 태스크 생성
    osThreadNew(Task1, NULL, NULL);
    osThreadNew(Task2, NULL, NULL);

    // OS 시작
    osKernelStart();

    for (;;);
}

결론

FreeRTOS(CMSIS v1)에서 Semaphore와 Mutex는 태스크 간 동기화와 리소스 보호를 위해 필수적인 메커니즘입니다. Semaphore는 신호 전달 및 다중 리소스 접근에, Mutex는 단일 리소스 보호에 적합합니다. 적절한 동기화 메커니즘을 선택하고 사용하는 것은 안정적이고 효율적인 시스템 설계의 핵심입니다. 위의 설명과 예제를 활용하여 FreeRTOS 기반 프로젝트에서 Semaphore와 Mutex를 효과적으로 적용해 보세요.

반응형

'FreeRTOS' 카테고리의 다른 글

FreeRTOS 타이머와 시간 관리  (0) 2025.01.15
FreeRTOS Queue와 데이터 통신  (0) 2025.01.13
FreeRTOS Task  (0) 2025.01.12
FreeRTOS 기본 개념과 구현 방법  (0) 2025.01.11
FreeRTOS 개발 환경 설정 및 구현 방법  (0) 2025.01.10