RTOS와 실시간 시스템의 스케줄링·동기화 설계
RTOS의 결정론적 응답, 선점형 스케줄링, 동기화 메커니즘과 FreeRTOS·QNX 등 주요 선택 기준을 정리한다.
2026-08-14 · 최초 발행 2026-01-12
마감 시각을 예측할 수 있어야 하는 운영체제
RTOS(Real-Time Operating System)는 작업 완료 시점이 예측 가능해야 하는 실시간 운영체제다. 단순히 빠르게 처리하는 것이 아니라, 정해진 데드라인 안에 작업을 마칠 수 있도록 우선순위 기반 스케줄링과 빠른 인터럽트 처리를 제공한다.
Hard Real-Time 환경에서는 데드라인 초과 자체가 시스템 실패다. 자동차 브레이크, 항공기 제어, 인공심장박동기가 여기에 해당한다. Soft Real-Time은 지연이 성능 저하로 이어지지만 시스템 실패로 보지는 않으며, 멀티미디어 스트리밍과 비디오 게임이 예다. Firm Real-Time에서는 마감 시각을 넘긴 결과가 무효가 된다. 오래된 센서 데이터가 대표적이다.
일반 OS가 처리량과 공정한 자원 분배를 우선한다면, RTOS는 응답 시간의 일관성을 우선한다.
| 특성 | RTOS | 일반 OS (Linux, Windows) |
|---|---|---|
| 목표 | 응답 시간 예측 가능성 | 처리량, 공정성 |
| 스케줄링 | 우선순위 기반 선점형 | 공정 분배 (CFS) |
| 인터럽트 응답 | 매우 빠름 (수 마이크로초) | 느림 |
| 커널 크기 | 작음 (수 KB ~ 수백 KB) | 큼 (수 GB) |
| 결정론적 동작 | 필수 | 선택적 |
| 용도 | 임베디드, 제어 시스템 | 범용 컴퓨팅 |
예측 가능한 실행 시간을 만드는 조건
RTOS의 결정론적 동작은 작업 실행 시간, 인터럽트 레이턴시, 컨텍스트 스위칭 시간을 예측 가능한 범위에 두는 데서 나온다. 이때 Worst-Case Execution Time(WCET) 분석이 필요하다.
태스크마다 우선순위를 지정하고 높은 우선순위의 태스크가 먼저 실행된다. 더 높은 우선순위의 태스크가 준비 상태가 되면, 실행 중인 낮은 우선순위 태스크를 중단하고 즉시 CPU를 넘겨받는다.
태스크 A (우선순위 10) 실행 중
태스크 B (우선순위 20) 준비 상태로 전환
→ 태스크 A 즉시 중단, 태스크 B 실행
인터럽트 발생부터 ISR 실행 시작까지의 시간을 인터럽트 레이턴시라고 한다. RTOS는 이를 수 마이크로초 이내로 다루며, 일반 OS에서는 수 밀리초 이상이 걸릴 수 있다. 크리티컬 섹션을 작게 유지해 인터럽트 비활성화 시간을 줄이는 방식이 필요하다.
커널은 필요한 기능만 포함하도록 구성된다. ROM/Flash는 수 KB ~ 수백 KB, RAM은 수 KB 수준의 footprint를 목표로 하며, 불필요한 기능은 제외한다.
커널과 태스크가 나누는 역할
커널은 태스크 스케줄링, 인터럽트 처리, 동기화 메커니즘 제공을 맡는다. FreeRTOS처럼 기능을 커널 공간에 두는 Monolithic 구조도 있고, QNX처럼 최소 기능만 커널에 두는 Microkernel 구조도 있다.
태스크는 독립적으로 실행되는 코드 단위로 스레드와 유사하다. 우선순위와 스택 크기를 가지며 Running, Ready, Blocked, Suspended 상태를 오간다.
Ready → Running: 스케줄러 선택
Running → Ready: 선점
Running → Blocked: 이벤트 대기 (세마포어, 큐)
Blocked → Ready: 이벤트 발생
스케줄러는 실행할 태스크를 선택하고 컨텍스트 스위칭을 수행한다. 우선순위 기반 정책을 사용하며 선점형 또는 비선점형으로 동작할 수 있다. 같은 우선순위의 태스크에는 Round-Robin 방식을 적용한다.
ISR은 하드웨어 인터럽트를 빠르게 처리하는 루틴이다. ISR 안에는 짧은 처리만 두고, 복잡한 작업은 태스크로 넘기는 Deferred Interrupt Processing 방식이 적합하다.
void UART_IRQHandler(void) {
// 하드웨어에서 데이터 읽기
char data = UART_ReadByte();
// 큐에 데이터 전달
xQueueSendFromISR(uart_queue, &data, NULL);
}
우선순위를 정하는 스케줄링 방식
Rate Monotonic Scheduling(RMS)은 주기가 짧은 태스크에 더 높은 고정 우선순위를 부여한다. CPU 사용률은 n(2^(1/n) - 1) 이하여야 하며, n은 태스크 수다. n=2일 때 약 83%이고 n이 무한대로 갈수록 약 69%가 된다.
태스크 A: 주기 10ms → 우선순위 높음
태스크 B: 주기 50ms → 우선순위 낮음
RMS는 단순하고 분석하기 쉽지만 CPU 사용률이 최대 69%로 제한된다.
Earliest Deadline First(EDF)는 데드라인이 가장 가까운 태스크에 높은 우선순위를 주며, 런타임에 우선순위가 변경된다. CPU 사용률은 100%까지 가능하지만 우선순위 재계산 오버헤드가 있고, 데드라인을 넘기면 연쇄 실패가 발생할 수 있다.
Priority-Based Preemptive Scheduling은 RTOS의 기본 알고리즘이다. 가장 높은 우선순위 태스크를 실행하고, 더 높은 우선순위 태스크가 준비 상태가 되면 즉시 선점한다. 동일 우선순위 태스크는 Round-Robin으로 처리한다.
공유 자원과 이벤트를 조율하는 방법
세마포어는 자원 개수를 관리한다. 카운팅 세마포어의 초기값은 사용 가능한 자원 수이며, 이진 세마포어는 0 또는 1로 상호 배제에 사용된다.
SemaphoreHandle_t xSemaphore;
// 세마포어 생성
xSemaphore = xSemaphoreCreateCounting(5, 5); // 최대 5, 초기 5
// 자원 획득 (P 연산)
xSemaphoreTake(xSemaphore, portMAX_DELAY);
// 크리티컬 섹션
// ...
// 자원 해제 (V 연산)
xSemaphoreGive(xSemaphore);
뮤텍스는 하나의 자원을 보호하며, 획득한 태스크만 해제할 수 있는 소유권을 가진다. 낮은 우선순위 태스크가 뮤텍스를 가진 상태에서 높은 우선순위 태스크가 대기하면, 우선순위 상속으로 소유 태스크의 우선순위를 일시적으로 올려 우선순위 역전을 방지한다.
SemaphoreHandle_t xMutex;
// 뮤텍스 생성
xMutex = xSemaphoreCreateMutex();
// 뮤텍스 획득
xSemaphoreTake(xMutex, portMAX_DELAY);
// 크리티컬 섹션
shared_resource++;
// 뮤텍스 해제
xSemaphoreGive(xMutex);
이벤트 플래그는 비트 플래그 집합으로 여러 조건을 기다리는 데 사용한다.
// 이벤트 A 또는 B 발생 대기
xEventGroupWaitBits(event_group, EVENT_A | EVENT_B, pdTRUE, pdFALSE, portMAX_DELAY);
// 이벤트 설정
xEventGroupSetBits(event_group, EVENT_A);
메시지 큐는 FIFO 구조로 태스크 간 데이터를 전달한다.
QueueHandle_t xQueue;
// 큐 생성 (10개 항목, 각 4바이트)
xQueue = xQueueCreate(10, sizeof(uint32_t));
// 송신
uint32_t data = 123;
xQueueSend(xQueue, &data, portMAX_DELAY);
// 수신
uint32_t received;
xQueueReceive(xQueue, &received, portMAX_DELAY);
용도와 제약에 따른 RTOS 선택
FreeRTOS는 MIT License 기반의 오픈소스 RTOS다. footprint는 4~9 KB이며 ARM Cortex-M, Cortex-A, AVR, PIC, RISC-V, x86을 지원한다. IoT, 마이크로컨트롤러, 저비용 임베디드 시스템에 쓰이며 Amazon(AWS IoT)이 개발사다.
VxWorks는 Hard Real-Time과 POSIX 호환을 제공하는 상용 RTOS다. NASA Mars Rover를 포함한 항공우주, 국방, 네트워크 장비에 사용되며 Wind River Systems가 개발했다.
QNX는 Microkernel 기반의 상용 RTOS다. POSIX 호환과 높은 안정성을 특징으로 하며 자동차 인포테인먼트, 의료 기기, 산업 제어에 사용된다. BlackBerry가 개발했고, QNX SDP는 상용이며 QNX for Academics는 오픈소스다.
ThreadX(Azure RTOS)는 작은 footprint와 우선순위 기반 선점형 스케줄링을 제공한다. IEC 61508, DO-178B 안전 인증을 받았고 IoT, 의료 기기, 항공우주에 사용된다. Microsoft Azure RTOS이며 2019년 이후 MIT License를 사용한다.
Zephyr는 Apache 2.0 기반의 모듈형 오픈소스 RTOS다. 풍부한 드라이버를 제공하고 ARM, RISC-V, x86을 지원한다. IoT와 웨어러블이 주요 용도이며 Linux Foundation의 후원을 받는다.
RT-Linux는 Linux에 PREEMPT_RT 패치를 적용해 Soft Real-Time을 제공한다. 산업 자동화와 로봇에 쓰이며 GPL 라이선스를 따른다.
자동차에서는 엔진 제어, ABS 브레이크, 에어백을 담당하는 ECU와 자율 주행·충돌 방지 ADAS에 적용된다. 항공기, 드론, 로켓의 비행 제어와 통신·관측 위성에도 사용된다. 인공심장박동기와 인공호흡기 같은 생명 유지 장치, 심전도(ECG)와 혈압 모니터링 장비도 실시간 처리가 필요한 영역이다. 공장 자동화와 로봇 제어를 위한 PLC, 정밀 가공 CNC 기계, 5G 네트워크 기지국의 데이터 처리 및 라우터·스위치의 패킷 처리 역시 RTOS 응용 분야다.
FreeRTOS로 태스크와 공유 자원 다루기
아래 예시는 서로 다른 우선순위의 태스크를 만들고 스케줄러를 시작하는 흐름이다.
#include "FreeRTOS.h"
#include "task.h"
void vTask1(void *pvParameters) {
while(1) {
// LED 토글
GPIO_TogglePin(LED_PIN);
vTaskDelay(pdMS_TO_TICKS(500)); // 500ms 대기
}
}
void vTask2(void *pvParameters) {
while(1) {
// 센서 읽기
uint32_t sensor_value = ADC_Read();
printf("Sensor: %u\n", sensor_value);
vTaskDelay(pdMS_TO_TICKS(1000)); // 1000ms 대기
}
}
int main(void) {
// 하드웨어 초기화
HAL_Init();
// 태스크 생성
xTaskCreate(vTask1, "Task1", 128, NULL, 2, NULL); // 우선순위 2
xTaskCreate(vTask2, "Task2", 256, NULL, 1, NULL); // 우선순위 1
// 스케줄러 시작
vTaskStartScheduler();
// 여기까지 도달하지 않음
while(1);
}
공유 버퍼를 생산자와 소비자 태스크가 함께 쓸 때는 뮤텍스로 접근을 보호할 수 있다.
SemaphoreHandle_t xMutex;
void vProducerTask(void *pvParameters) {
while(1) {
xSemaphoreTake(xMutex, portMAX_DELAY);
// 공유 자원 쓰기
shared_buffer[write_index++] = data;
xSemaphoreGive(xMutex);
vTaskDelay(pdMS_TO_TICKS(100));
}
}
void vConsumerTask(void *pvParameters) {
while(1) {
xSemaphoreTake(xMutex, portMAX_DELAY);
// 공유 자원 읽기
uint32_t data = shared_buffer[read_index++];
xSemaphoreGive(xMutex);
printf("Data: %u\n", data);
vTaskDelay(pdMS_TO_TICKS(200));
}
}
int main(void) {
xMutex = xSemaphoreCreateMutex();
xTaskCreate(vProducerTask, "Producer", 128, NULL, 2, NULL);
xTaskCreate(vConsumerTask, "Consumer", 128, NULL, 2, NULL);
vTaskStartScheduler();
while(1);
}
요구사항에 맞춰 검토할 항목
Hard Real-Time 요구에는 VxWorks, QNX, ThreadX를 검토할 수 있고, Soft Real-Time에는 FreeRTOS와 RT-Linux가 해당한다.
RAM < 64KB처럼 자원이 극도로 제한된 환경에는 FreeRTOS와 Zephyr가 적합하다. RAM이 수 MB인 중간 수준 환경에서는 ThreadX와 FreeRTOS를, RAM이 수십 MB 이상으로 풍부한 환경에서는 QNX와 RT-Linux를 선택 후보로 둘 수 있다.
IEC 61508 또는 DO-178B 안전 인증이 필요하면 VxWorks, ThreadX, QNX를 검토한다. 오픈소스 라이선스가 조건이라면 FreeRTOS(MIT), Zephyr(Apache 2.0), RT-Linux(GPL)가 대상이며, VxWorks와 QNX는 상용 선택지다.