
운영체제(OS)는 기본적으로 자원 관리자(Resource Manager)이다. OS는 HW 주변 장치를 제어하고 Task을 스케줄링한다. 이러한 방식으로 시스템의 모든 부분에 자원을 할당한다.
이어서 RTOS(Real Time Operating System)도 OS의 기능을 수행하지만, 추가로 데드라인(deadline)을 보장한다. 다시 말해, RTOS은 Task가 정해진 시간에 반드시 실행 완료되도록 보장한다. 즉, 단순히 Task가 실행되는 것뿐만 아니라, 언제 실행되는지가 중요하다.
RTOS와 범용 OS를 비교해보면, RTOS가 오히려 단순할 것이다. 왜냐하면 특수한 목적의 작업만 수행하기 때문이다.
예를 들어, 범용 OS인 Windows 8은 문서 작성, 게임 실행, 이메일 송수신, 소프트웨어 컴파일, 영화 감상 등 컴퓨터 장치에서 요구되는 거의 모든 종류의 작업을 수행하도록 만들어져 있다. 반면, ATM 기기에서 동작하는 RTOS을 생각해보면, 이 OS가 수행해야 하는 작업은 은행 네트워크 연결, 현금 인출, 잔액 계산, 사용자 인증 등 소수의 작업에 불과하다.
또한, RTOS는 time-constraint 내에서 동작하며, 훨씬 더 예측 가능한 행동을 보인다는 특징도 있다.
RTOS의 성능을 측정하기 위해 다양한 성능 지표가 존재한다. 다음은 가장 흔히 사용되는 지표이다.
① 데드라인(Deadline)
RTOS가 time-constraint 내에서 올바른 결과를 도출하는 지 측정하는 데 사용
② 신뢰성(Reliability)
RTOS가 예측 가능한 방식으로 동작하며, 응답을 보장하는 지 측정하는 데 사용
임베디드 프로그램이 어떻게 구성되는지 살펴보겠다. 예를 들어, 자율 주행 차량을 위한 펌웨어를 설계한다고 가정해보겠다. 그리고 이 차량에는 라이다(Lidar), 레이더(Radar), 카메라(Camera) 등 세 개의 센서가 있다고 하겠다. 펌웨어를 Sequential Program 방식으로 구현한다면 구조는 다음과 비슷할 것이다.

먼저 라이다의 상태를 확인한다. 만약 새로운 데이터가 있으면 해당 데이터를 수집하고 다음 코드 라인으로 넘어간다. 새로운 데이터가 없거나 센서가 바쁘더라도, 여전히 다음 코드 라인으로 진행한다. 그리고 같은 방식으로 레이더, 카메라의 상태를 확인한다. 마지막에는 제동을 걸거나, 좌회전·우회전하는 등의 동작을 수행한다.
프로그래밍 용어로는 이를 Busy Wait 방식이라고 부른다. 이 방식은 단순한 문제에는 적절할 수 있지만, 위에 제시된 자율주행차 흐름도를 보면, 심각한 문제가 있다.
예를 들어, 카메라 센서를 읽는 도중에 라이다의 상태가 바뀌었다고 가정해보겠다. 차량이 실제로 제동이나 회전 같은 동작을 취하는 순간에는, 라이다 데이터가 이미 갱신되지 않은 오래된 값일 수 있다. 이런 정보에 의존해 움직인다면 사고로 이어질 수 있다.
앞서 언급된 문제를 멀티스레드 접근 방식으로 해결해보고자 한다.

예를 들어, 센서 데이터를 Background Thread에서 수집하고, 새로운 데이터가 생길 때마다 또는 정해진 일정한 주기마다 그 데이터를 Foreground Thread(Main Thread)로 전달한다고 하겠다. 이렇게 되면 모든 센서가 동시에 데이터를 수집할 수 있다. 즉, 세 개의 Background Thread를 두고, 하나는 라이다(LiDAR) 데이터를, 다른 하나는 레이더(Radar) 데이터를, 그리고 마지막 하나는 카메라(Camera) 데이터를 수집하도록 하는 것이다. 여기서 Background Thread는 ISR1, ISR2, ISR3로 표기된다.
참고로 ISR(Interrupt Service Routine)은 인터럽트 핸들러(Interrupt Handler)라고도 불리며, 레이더와 같은 특정 입력 장치에서 새로운 데이터가 발생했을 때 실행된다. 또한, Timer Interrupt을 이용하면 특정 주기마다 Task을 실행할 수도 있다. 여기서 말하는 Task란 ISR1, ISR2, ISR3 같은 함수를 의미한다. 한편, Foreground Thread는 나머지 시간 동안 실행된다. 이런 방식을 ISR 기반 접근법이라고 한다.
만약 각 ISR에 서로 다른 우선순위를 부여하여, 항상 더 높은 우선순위를 가진 ISR이 먼저 실행되도록 한다면, 이 시스템은 Soft RTOS가 된다. 이는 첫 번째 모델보다 발전된 방식이지만, 여전히 문제가 존재한다.
앞서 말했듯이, Foreground Thread는 남는 시간에만 실행된다. 하지만 이는 자율주행차 같은 Real-Time System에는 용납될 수 없다. 왜냐하면 Real-Time System의 핵심 특징은 time-constraint 내에서 올바른 결과를 도출하는 능력이다. 지금 설명한 방식만으로는 이 조건을 완전히 충족할 수 없다.
여기서 필요한 것은, 여러 개의 Foreground Threads와 이들 사이에서 상호작용할 수 있도록 돕는 Synchronization Tools가 제공되는 시스템이다.
정해진 time-constraint 내에 올바른 결과를 내기 위해서는 모든 Tasks을 Foreground Thread에서 실행해야 한다. 단, 지금까지처럼 순서대로가 아니라 마치 동시에 실행되는 것처럼 해야 한다.

우리가 원하는 것은 각 Task을 Main Task처럼 따로 실행하는 것이다. 예를 들어, Task 1은 차량 제어(브레이크, 회전 등)를 담당하고, Task 2는 라이다 데이터를 처리하는 식인 것이다.
그리고 이렇게 모든 작업을 동시에 이루어지듯 실행해서 제한된 시간 안에 결과를 내기 위해 필요한 것이 바로 Thread Scheduler이다.
기본적으로 Thread란 Task의 실행을 의미한다. 앞선 자율주행차 예시를 떠올려보면, Task 1은 Take Action인데, 이것이 실행되면 곧 Take Action Thread을 의미한다. 다른 Task도 마찬가지이다.
모든 Thread는 실행할 프로그램을 가지고 있으며, 같은 프로그램을 여러 Threads가 동시에 실행할 수도 있다. 각각의 Thread는 고유하게 레지스터 집합, 스택, 실행할 프로그램을 가진다.
그런데 여태 다뤄왔던 프로세서에는 Register Bank가 하나뿐이라고 해왔다. 여기서 Thread가 각각의 Register을 가질 수 있다는 점에 상충된다. Thread Scheduler가 이를 해결한다.
만약 MiCOM 내 프로세서가 네 개의 CPU를 가지고 있다면, 네 개의 Threads을 병렬로 실행하기에 충분한 자원과 Register Bank가 있을 것이다. 하지만 Single-Core에서는 그런 환경을 만들 수 없다.
따라서 OS는 여러 CPU가 있는 것처럼 흉내를 내야 한다. 심지어 다중 코어를 가진 마이크로프로세서도 실제로는 CPU 개수보다 더 많은 Threads를 실행해야 하는데, 여기서 Thread Scheduler가 유용하게 쓰인다.
① Sporadic Thread
② Periodic Thread
③ Aperiodic Thread
① Flag Thread
② Input-Triggered Thread
③ Output-Triggered Thread