RTOS는 정말 동시에 실행할까? Task·Scheduler·Context Switch 정리

카드뉴스

단일 코어에서 Running Task는 한 번에 하나다

Task를 여러 개 만들어도 단일 코어 MCU가 같은 순간에 여러 Task의 명령을 실행하는 것은 아니다. CPU를 실제로 쓰는 Running Task는 한 시점에 하나이며, RTOS가 실행 대상을 빠르게 바꿔 여러 작업이 함께 진행되는 것처럼 보이게 한다. 이것이 concurrency다.

DMA, Timer, UART 같은 주변장치는 CPU와 독립적으로 동작할 수 있다. 인터럽트도 실행 중인 Task를 잠시 중단시킬 수 있지만, 한 CPU 코어에서 여러 Task가 동시에 Running이 되는 것은 아니다. 코어가 둘 이상인 시스템에서는 각 코어가 하나씩 맡아 실제 parallelism이 가능하다.

Scheduler는 우선순위와 Task 상태를 함께 본다

Task는 보통 Ready, Running, Blocked 상태를 오간다. Ready는 실행 조건을 갖추고 CPU를 기다리는 상태이고, Blocked는 delay가 끝나거나 queue, semaphore, notification 같은 이벤트가 오기를 기다리는 상태다. Blocked Task는 기다리는 동안 CPU 시간을 쓰지 않는다.

선점형 설정에서는 더 높은 우선순위 Task가 Ready가 되면 현재 Task를 중단하고 실행할 수 있다. 협력형에서는 현재 Task가 yield하거나 Blocked 상태로 들어갈 때 전환된다. 같은 우선순위 사이의 time slicing도 설정에 따라 달라지므로 `configUSE_PREEMPTION`, `configUSE_TIME_SLICING` 같은 실제 구성값을 확인해야 한다.

Context Switch는 중단 지점을 보관하고 되살린다

실행 대상을 바꿀 때 RTOS는 현재 Task가 나중에 같은 위치에서 이어갈 수 있도록 Program Counter, Stack Pointer, CPU register와 상태 정보를 저장한다. 각 Task는 자신의 stack을 가지며, Task Control Block에는 stack 위치와 현재 상태 같은 스케줄링 정보가 연결된다.

다음 Task의 context를 복원하면 그 Task는 이전에 멈춘 지점부터 다시 실행한다. 저장 범위는 CPU 구조와 RTOS port에 따라 달라지고 전환 자체에도 시간이 든다. Task 수를 늘리거나 너무 자주 깨우면 context switch와 stack 사용량이 함께 커질 수 있다.

높은 우선순위 Task도 기다릴 때는 Blocked가 되어야 한다

높은 우선순위 Task가 이벤트를 기다리면서 busy loop를 돌면 계속 Ready 또는 Running 상태에 남는다. 그러면 낮은 우선순위 Task는 CPU를 받지 못하는 starvation 상태가 될 수 있다. 기다림은 queue receive, semaphore take, notification wait, delay처럼 Task를 Blocked로 보내는 방식으로 표현하는 편이 맞다.

스케줄링 문제를 볼 때는 우선순위 숫자만 비교하지 말고 각 Task가 언제 Ready가 되고 어디서 Blocked되는지 시간 순서로 그려 보자. 한 시점의 Running Task와 전환 조건을 표시하면 “동시에 실행된다”는 인상 대신 실제 CPU 점유 흐름을 확인할 수 있다.

댓글 남기기