승코딩당당당
[RTOS] RTOS에서 Mutex 동작 실습 및 이론 정리 본문
RTOS 환경에서는 여러 태스크가 동시에 실행되며, 동일한 자원에 접근할 경우 데이터 충돌이 발생할 수 있다.
이를 방지하기 위해 동기화 기법이 필요하며, 대표적인 방법이 Mutex이다.
본 글에서는 Mutex의 개념을 간단히 정리하고, OSEK/Trampoline 환경에서 직접 구현한 Mutex를 활용하여
태스크 간 동기화가 어떻게 이루어지는지 실습을 통해 확인하였다.
Mutex의 개념
Mutex(Mutual Exclusion)는 하나의 공유 자원에 대해 동시에 하나의 태스크만 접근하도록 제한하는 동기화 기법이다.
즉, 특정 자원을 사용하려는 태스크는 먼저 lock을 획득해야 하며,
이미 다른 태스크가 해당 자원을 사용 중이라면 접근할 수 없고 대기 상태에 들어가게 된다.
✔ 특징
- 한 번에 하나의 태스크만 접근 가능
- lock / unlock 구조로 동작
- 공유 자원의 일관성 유지
- 태스크 간 충돌(Race Condition) 방지
RTOS에서의 Mutex 동작
RTOS에서는 Mutex가 단순한 변수 lock이 아니라,
태스크의 실행 상태를 제어하는 동기화 도구로 사용된다.
- Mutex를 획득하지 못한 태스크는 block 상태로 전환
- Mutex가 해제되면 해당 태스크는 wakeup되어 실행 재개
즉, Mutex는 데이터 보호뿐 아니라 스케줄링 흐름에도 직접적인 영향을 준다.
실습 환경
- RTOS: OSEK / Trampoline
- 보드: Arduino UNO
- 개발환경: goil + make.py
- 사용 개념: Task, Event, Mutex
📌 코드 파일 구성 및 설명
1. asw.c (Application Software)
본 파일은 RTOS 상에서 실행되는 애플리케이션 로직을 담당하는 코드로,
실제 Mutex 동작을 확인하기 위한 태스크들이 정의되어 있다.
✔ 주요 역할
- TaskL, TaskH : Mutex를 사용하는 두 개의 태스크
- TickPrint : 주기적으로 실행되며 태스크 실행 순서를 제어
TickPrint → TaskL 실행 → Mutex 획득
→ TaskH 실행 → Mutex 요청 → Block
→ TaskL Release → TaskH 실행 재개
#include "bsw.h"
#include "mutex.h"
MutexType s1;
TASK(TaskH)
{
printfSerial("<TaskH begins,> ");
mdelay(1000);
printfSerial("TaskH : Try Lock(s1). ");
GetMutex(&s1);
printfSerial("TaskH : Get Lock(s1). ");
mdelay(3000);
printfSerial("TaskH : Release Lock(s1). ");
ReleaseMutex(&s1);
mdelay(1000);
printfSerial("<TaskH ends.> ");
TerminateTask();
}
TASK(TaskL)
{
printfSerial("<TaskL begins,> ");
mdelay(2000);
printfSerial("TaskL : Try Lock(s1). ");
GetMutex(&s1);
printfSerial("TaskL : Get Lock(s1). ");
mdelay(5000);
printfSerial("TaskL : Release Lock(s1). ");
ReleaseMutex(&s1);
mdelay(1000);
printfSerial("<TaskL ends.> ");
TerminateTask();
}
/* This task will be activated every second */
TASK(TickPrint)
{
static long c = -4;
printfSerial("\n%4ld: ", c++);
if (c == -2)
InitMutex(&s1, Event1);
else if (c == 0)
ActivateTask(TaskL);
else if (c == 5)
ActivateTask(TaskH);
TerminateTask();
}
- GetMutex(&s1)
→ Mutex 획득 시도 (이미 점유 중이면 block) - ReleaseMutex(&s1)
→ Mutex 해제 (대기 태스크 wakeup) - ActivateTask(TaskL / TaskH)
→ 특정 시점에 태스크 실행
2. mutex.c (Mutex 구현)
본 파일은 Mutex의 실제 동작을 구현한 코드로,
태스크 간 동기화를 수행하는 핵심 로직이 포함되어 있다.
✔ 주요 역할
- Mutex 초기화
- Mutex 획득 (Lock)
- Mutex 해제 (Unlock)
- 태스크 block / wakeup 처리
#include "bsw.h"
#include "mutex.h"
void InitMutex(MutexType *mutex, EventMaskType event)
{
mutex->flag = UNLOCKED;
mutex->waiting_task = -1;
mutex->event = event;
mutex->has_waiter = 0;
}
void GetMutex(MutexType *mutex)
{
if (mutex->flag == LOCKED) {
printfSerial(" --> Block");
mutex->has_waiter = 1;
GetTaskID(&(mutex->waiting_task));
WaitEvent(mutex->event);
ClearEvent(mutex->event);
}
mutex->flag = LOCKED;
}
void ReleaseMutex(MutexType *mutex)
{
if (mutex->flag == LOCKED) {
mutex->flag = UNLOCKED;
if (mutex->has_waiter) {
SetEvent(mutex->waiting_task, mutex->event);
mutex->has_waiter = 0;
}
}
}
InitMutex
- Mutex 상태를 UNLOCKED로 초기화
- 대기 태스크 정보 초기화
GetMutex
- 이미 lock 상태인 경우
→ 현재 태스크를 waiting 상태로 저장
→ WaitEvent로 block 상태 진입 - lock이 가능하면 flag를 LOCKED로 변경
ReleaseMutex
- lock 해제대기 태스크가 있으면 SetEvent로 wakeup
3. mutex.h (Mutex 정의)
본 파일은 Mutex 구조체와 관련 함수들을 정의한 헤더 파일이다.
✔ 주요 역할
- Mutex 자료형 정의
- 상태값 정의 (LOCKED / UNLOCKED)
- 함수 선언
#ifndef MUTEX_H_
#define MUTEX_H_
#include "bsw.h"
#define LOCKED 1
#define UNLOCKED 0
typedef struct _MutexType {
int flag;
int has_waiter;
EventMaskType event;
TaskType waiting_task;
} MutexType;
void InitMutex(MutexType *mutex,
EventMaskType event);
void GetMutex(MutexType *mutex);
void ReleaseMutex(MutexType *mutex);
#endif /* MUTEX_H_ */
- flag
→ Mutex의 현재 상태 (lock 여부) - has_waiter
→ 대기 중인 태스크 존재 여부 - event
→ 태스크를 깨우기 위한 이벤트 - waiting_task
→ block 상태로 들어간 태스크 ID
4. OIL 파일 (RTOS 설정)
본 파일은 OSEK RTOS에서 사용하는 설정 파일로,
태스크, 이벤트, 스케줄링 등을 정의한다.
✔ 주요 역할
- Task 정의
- Priority 설정
- Event 정의
- Alarm을 통한 주기 실행 설정
/* Running the following example:
* just call goil a first time using the command line:
* goil --target=avr/arduino/uno --templates=../../../../goil/templates/ serial.oil
* you may have to update ARDUINO section (l.13) for your configuration.
*
*/
OIL_VERSION = "2.5" : "test" ;
CPU test {
OS config {
STATUS = STANDARD;
BUILD = TRUE {
TRAMPOLINE_BASE_PATH = "../..";
APP_NAME = "base";
APP_SRC = "bsw.cpp";
APP_SRC = "asw.c";
APP_SRC = "mutex.c";
LDFLAGS = "-Wl,-Map=counter.map";
CPPCOMPILER = "avr-g++";
COMPILER = "avr-gcc";
LINKER = "avr-gcc";
ASSEMBLER = "avr-gcc";
COPIER = "avr-objcopy";
SYSTEM = PYTHON;
LIBRARY = serial;
};
SYSTEM_CALL = TRUE;
};
APPMODE stdAppmode {};
/* The following code block is for basic features of the labs */
COUNTER DefaultTimer {
SOURCE = TIMER2_OVF;
TICKSPERBASE = 1;
MAXALLOWEDVALUE = 2000;
MINCYCLE = 1;
};
ALARM TimerAlarm {
COUNTER= DefaultTimer;
ACTION = ACTIVATETASK {
TASK = TickPrint;
};
AUTOSTART = TRUE {
// note: no more than 255 => MAXALLOWEDVALUE in counter
ALARMTIME = 977;
CYCLETIME = 977; //activated each 1000 ms
APPMODE = stdAppmode;
};
};
TASK TickPrint {
PRIORITY = 20;
AUTOSTART = FALSE;
ACTIVATION = 1;
SCHEDULE = FULL;
STACKSIZE = 256;
};
/* The above code block is for basic features of the labs */
/* Fill up your code in here */
EVENT Event1 { MASK = AUTO; };
TASK TaskL {
PRIORITY = 1;
AUTOSTART = FALSE;
ACTIVATION = 1;
SCHEDULE = FULL;
STACKSIZE = 256;
EVENT = Event1;
};
TASK TaskH {
PRIORITY = 2;
AUTOSTART = FALSE;
ACTIVATION = 1;
SCHEDULE = FULL;
STACKSIZE = 256;
EVENT = Event1;
};
};
결과

TaskL 시작 → Mutex 획득
↓
TaskH 시작 → Mutex 요청 → Block
↓
TaskL 종료 → Mutex Release
↓
TaskH wakeup → Mutex 획득 → 실행
TaskH는 높은 우선순위를 가지지만, Mutex가 점유된 상태에서는 즉시 실행되지 못하고 block 상태로 대기하며,
Mutex 해제 시점에 wakeup되어 실행되는 것을 확인할 수 있었다.

'개발 > 임베디드' 카테고리의 다른 글
| [RTOS] OSEK/Trampoline RTOS Task 스케줄링 실습 (0) | 2026.04.24 |
|---|---|
| [RTOS] RTOS Scheduling과 OSEK 개념 정리 (0) | 2026.04.23 |
| [차량 통신] SDV 전환과 차량 통신 구조 정리 (CAN vs Ethernet) (0) | 2026.04.21 |
| [차량 통신] 차량 네트워크 구조 정리 (CAN, Ethernet, TCP/IP) (0) | 2026.04.16 |
| [차량 통신] CAN, FlexRay, LIN, SOME/IP (0) | 2026.04.14 |