선점형 스케줄링 (Preemptive Scheduling)

핵심 인사이트 (3줄 요약)

  1. 본질: 선점형 스케줄링 (Preemptive Scheduling)은 운영체제가 현재 실행 중인 프로세스의 CPU 제어권을 강제로 빼앗아 (Preempt) 다른 우선순위가 높거나 할당된 시간이 도래한 프로세스에게 넘겨주는 방식이다.
  2. 가치: 특정 프로세스의 CPU 독점을 방지하여 시분할 시스템 (Time-sharing System)과 실시간 시스템 (Real-time System)에서 필수적인 '빠르고 일관된 응답성 (Responsiveness)'을 보장한다.
  3. 융합: 선점 동작은 타이머 인터럽트 (Timer Interrupt)라는 하드웨어의 지원에 전적으로 의존하며, 잦은 문맥 교환 (Context Switch) 오버헤드와 공유 자원 접근 시 경쟁 조건 (Race Condition)이라는 심각한 동기화 문제를 야기한다.

Ⅰ. 개요 및 필요성 (Context & Necessity)

  • 개념: 프로세스 스케줄링 패러다임의 양대 산맥 중 하나로, 한 프로세스가 CPU를 할당받아 실행 중이더라도 커널이 개입하여 실행 상태 (Running)의 프로세스를 강제로 준비 상태 (Ready)로 쫓아내고 새로운 프로세스를 실행할 수 있는 방식이다.
  • 필요성: 만약 비선점 (Non-preemptive) 방식만 존재한다면, 악의적이거나 무한 루프에 빠진 프로그램 하나가 전체 시스템을 멈추게 할 수 있다. 또한 수많은 사용자가 마우스 클릭이나 키보드 입력을 할 때, 커널이 즉각적으로 UI 렌더링 프로세스로 문맥을 교환해 주지 않으면 심각한 프리징 현상을 겪게 된다.
  • 💡 비유: 노래방에서 아무리 노래를 계속 부르고 싶어 하는 사람이라도, 예약된 1시간이 끝나면 기계가 강제로 반주를 끄고 다음 사람에게 마이크를 넘기는 **'시간제 강제 종료 시스템'**과 같다.
  • 등장 배경: 과거 일괄 처리 (Batch) 시스템 시절에는 작업이 끝날 때까지 기다려주는 비선점 방식이 자원 효율 (처리량) 면에서 유리했다. 그러나 터미널을 통한 다중 사용자 대화형 (Interactive) 시스템이 도래하면서 응답 시간이 핵심 지표로 부상했고, 하드웨어 타이머의 발명과 함께 선점형 OS(Windows 95, Linux 등)가 업계 표준으로 자리 잡았다.
  [선점형 (Preemptive) vs 비선점형 (Non-preemptive) 흐름 차이]

  (비선점형 흐름)
  프로세스 A: [████████ 무한 루프 독점 ██████████████████████......]
  프로세스 B: (Ready) ........................................ (계속 대기)
  
  (선점형 흐름)
  프로세스 A: [████] (강제 쫓겨남) ........ [████] (쫓겨남)
                   ↓                     ↑
  인터럽트 발생 :   (타이머)              (타이머)
                   ↓                     ↑
  프로세스 B:      [████] (강제 쫓겨남) ........ [████]

[다이어그램 해설] 비선점 방식에서는 A가 스스로 I/O 대기를 하거나 종료(Exit)를 선언하기 전까지 B는 절대 실행될 수 없다. 반면 선점형 방식에서는 하드웨어에서 주기적으로 쏘아주는 타이머 인터럽트에 맞춰 운영체제가 강제 개입한다. 이 짧은 간격 덕분에 사용자는 A와 B가 "동시에" 실행되는 듯한 환상(Concurrency)을 경험하게 된다.

  • 📢 섹션 요약 비유: 축구 경기에서 체력이 남았다고 선수가 안 나가고 버티면 팀이 망가집니다. 감독(OS 커널)이 시간이 되면 강제로 교체 카드를 들어 선수를 벤치로 불러들이는 것이 팀(시스템) 전체의 밸런스를 살리는 길입니다.

Ⅱ. 아키텍처 및 핵심 원리 (Deep Dive)

선점이 발생하는 4가지 주요 시점 (트리거)

  1. Running → Ready (타임 슬라이스 소진): 프로세스에 할당된 퀀텀(Quantum)이 만료되어 하드웨어 타이머 인터럽트가 발생했을 때.
  2. Waiting → Ready (이벤트 완료 및 우선순위 역전): I/O 대기 중이던 프로세스의 작업이 완료되어 Ready 큐로 돌아왔는데, 이 프로세스의 우선순위가 현재 Running 중인 프로세스보다 높을 때 커널은 즉각 선점해 버린다.
  3. New → Ready (고우선순위 프로세스 생성): 새로운 프로세스가 생성되었는데, 그 우선순위가 현재 프로세스보다 높을 때.
  4. 시스템 콜 복귀 시점: 커널 모드에서 사용자 모드로 복귀 (Return from Interrupt/Syscall)하기 직전, 스케줄러를 호출하여 need_resched 플래그를 확인하고 다른 프로세스로 전환할 때.

심층 동작 원리 (타이머 인터럽트 기반 선점)

선점형 스케줄링의 근간은 '인터럽트 주도적 (Interrupt-driven)'이라는 데 있다.

  1. 하드웨어 타이머 세팅: 커널은 부팅 시 시스템 타이머 칩(PIT, APIC 등)에 특정 주파수(예: 1ms 혹은 10ms 단위, 100Hz~1000Hz)로 인터럽트(IRQ 0)를 발생시키도록 설정한다. 이 간격을 틱 (Tick) 또는 **지피스 (Jiffies)**라고 한다.
  2. 타이머 인터럽트 발생: 프로세스(User Mode)가 열심히 연산 중일 때, 하드웨어가 타이머 인터럽트를 쏘면 무조건 현재 레지스터 상태를 스택에 밀어 넣고 커널(ISR, 인터럽트 서비스 루틴)로 제어권이 넘어간다.
  3. 타임 퀀텀 삭감: 커널의 타이머 핸들러는 현재 Running 중인 프로세스의 PCB를 열어 time_slice 카운터를 1 줄인다.
  4. need_resched 플래그 활성화: 카운터가 0이 되면 이 프로세스는 더 이상 실행될 자격이 없으므로, 현재 프로세스의 구조체에 "스케줄링이 필요함(need_resched = 1)" 깃발을 꼽는다.
  5. 스케줄러(단기) 호출 및 문맥 교환: 인터럽트 처리가 끝나고 User Mode로 복귀하기 직전, need_resched가 1인 것을 보고 스케줄러가 개입(선점)한다. 디스패처를 통해 현재 프로세스를 Ready로 내리고 새로운 프로세스를 Running으로 올린다.
  ┌────────────────────────────────────────────────────────────────┐
  │          타이머 인터럽트 기반의 프로세스 강제 선점 구조도      │
  ├────────────────────────────────────────────────────────────────┤
  │                                                                │
  │   [하드웨어 계층]                                              │
  │   타이머 (Timer) ─────────(Tick 발생, 예: 1ms 마다)─────┐      │
  │                                                      │         │
  │                                                [IRQ 발생]      │
  │                                                      ▼         │
  │   [CPU 코어]                                                   │
  │   User Mode: 프로세스 P1 실행 중 (Time Slice=2)                │
  │        ↓                                                       │
  │   (Context 강제 저장) ◀────────── (하드웨어 인터럽트 개입!)    │
  │        ↓                                                       │
  │   Kernel Mode 진입:                                            │
  │   1. 타이머 ISR (Interrupt Service Routine) 실행               │
  │   2. P1의 Time Slice 차감 (2 -> 1, 아직 0 아님)                │
  │   3. User Mode로 복귀 (P1 계속 실행)                           │
  │                                                                │
  │   ... (1ms 후 다시 Tick 발생) ...                              │
  │                                                                │
  │   Kernel Mode 진입:                                            │
  │   1. P1의 Time Slice 차감 (1 -> 0!)                            │
  │   2. P1의 need_resched = 1 세팅                                │
  │   3. [스케줄러 호출!]                                          │
  │      - P1을 Ready Queue로 이동                                 │
  │      - P2를 Ready Queue에서 꺼냄                               │
  │   4. [디스패처 호출!]                                          │
  │      - P2의 Context 복원                                       │
  │   5. User Mode로 복귀 (P2 실행 시작)                           │
  └────────────────────────────────────────────────────────────────┘

[다이어그램 해설] 선점 메커니즘이 소프트웨어가 아닌 하드웨어의 무자비한 강제력(인터럽트)에 의존하고 있음을 보여준다. 커널 스스로 타이머가 없다면 루프를 도는 사용자 프로세스로부터 제어권을 영원히 찾아올 방법이 없다. 인터럽트 발생 → 커널 진입 → 퀀텀 검사 → 스케줄러 호출의 과정이 1초에도 수백 번씩 일어나며 시스템의 호흡(Tick)을 만들어낸다.

  • 📢 섹션 요약 비유: 수업 시간에 조는 학생을 깨우기 위해 선생님이 10분마다 주기적으로 치는 '알람 종'과 같습니다. 이 알람이 울려야만 선생님(커널)은 무조건 발언권을 얻어 교실(CPU)의 주도권을 통제할 수 있습니다.

Ⅲ. 융합 비교 및 다각도 분석 (Comparison & Synergy)

선점형 vs 비선점형 (Preemptive vs Non-preemptive)

비교 항목선점형 스케줄링 (Preemptive)비선점형 스케줄링 (Non-preemptive)
CPU 제어권 박탈운영체제 (타이머/우선순위 기반 강제 뺏음)프로세스 본인 (I/O, 종료 등 스스로 양보)
장점뛰어난 응답성 보장, 실시간 시스템 구현 가능문맥 교환 오버헤드 최소, 일괄 처리량(Throughput) 우수
단점 (오버헤드)잦은 문맥 교환으로 인한 캐시 무효화 (TLB Flush)CPU 독점으로 인한 기아(Starvation) 및 프리징 위험
동기화 이슈 (Race Condition)매우 심각함 (데이터 갱신 중 선점당할 위험)상대적으로 덜함 (원할 때 양보하므로 안전 구간 확보 가능)
대표 알고리즘라운드 로빈(RR), SRTF, 멀티레벨 큐, CFSFCFS, SJF, HRN

선점형 커널(Preemptive Kernel)과 시스템 콜

사용자 모드에서 선점당하는 것은 당연하다. 그렇다면 프로세스가 커널 영역(시스템 콜)의 코드를 실행하고 있을 때 (Kernel Mode) 선점당할 수 있는가? 과거 유닉스나 초기 리눅스는 "비선점형 커널 (Non-preemptive Kernel)"이었다. 즉, 프로세스가 시스템 콜을 통해 커널 내부 데이터를 조작하는 도중에는 절대 다른 프로세스로 전환하지 않았다. 그러나 이는 실시간(Real-time) 응답성에 치명적이었다. 현대 리눅스(2.6 이후)와 Windows는 **선점형 커널 (Preemptive Kernel)**로 진화하여, 커널 내부 코드를 실행하는 와중에도 (임계 구역(Critical Section) 스핀락 구간만 아니라면) 강제로 쫓겨날 수 있게 만들었다.

  ┌──────────┬─────────────────────────┬────────────────────────────┐
  │ 발생 위치│ 비선점형 커널 (예전)     │ 선점형 커널 (현대 OS)     │
  ├──────────┼─────────────────────────┼────────────────────────────┤
  │ User Mode│ 타이머에 의해 강제 선점됨│ 타이머에 의해 강제 선점됨 │
  │          │ (응답성 좋음)            │ (응답성 좋음)             │
  ├──────────┼─────────────────────────┼────────────────────────────┤
  │ Kernel   │ 시스템 콜(커널 로직)이   │ 커널 로직 실행 중에도     │
  │ Mode     │ 끝날 때까지 선점 금지    │ 즉각 선점 가능!           │
  │          │ (동기화 단순, 응답 지연) │ (동기화 극악, 응답성 최고)│
  └──────────┴─────────────────────────┴────────────────────────────┘
  • 📢 섹션 요약 비유: 비선점형 커널은 은행 직원이 고객 돈통을 열어 작업하는 중에는 은행 문을 잠그고 외부 전화를 안 받는 것이고, 선점형 커널은 돈통을 열고 돈을 세는 와중에도 비상 알람이 울리면 돈통을 즉시 봉인하고 밖으로 튀어 나가는 고도의 훈련된 시스템입니다.

Ⅳ. 실무 적용 및 기술사적 판단 (Strategy & Decision)

실무 시나리오

  1. 경쟁 조건 (Race Condition)과 락(Lock) 지옥: A 프로세스가 공유 메모리(Linked List)의 포인터를 수정하는 도중에 타임 퀀텀이 다 되어 선점당했다. 이후 B 프로세스가 CPU를 잡고 같은 리스트에 접근하면 데이터 구조가 망가져 커널 패닉이 발생한다.
    • 기술사적 결단: 선점형 스케줄링 환경에서는 공유 데이터 접근 시 반드시 뮤텍스(Mutex), 세마포어(Semaphore), 혹은 스핀락(Spinlock)으로 임계 구역(Critical Section)을 감싸야 한다. 특히 커널 코드는 선점될 때를 대비해 로컬 CPU 인터럽트를 비활성화(Disable Interrupt)하거나 커널 락을 쥐는 복잡한 동기화 프로그래밍이 필수적이다.
  2. 실시간 (Real-Time) 처리 실패 문제: 자율주행 자동차의 브레이크 제어 태스크(최우선순위)가 활성화되었는데, 내비게이션 태스크가 커널 내부 시스템 콜을 길게 실행 중이라면 선점하지 못하고 지연(Latency)이 발생해 사고로 이어진다.
    • 아키텍처 결단: 리눅스에 PREEMPT_RT 패치를 적용하여, 기존 커널의 거의 모든 스핀락(선점 불가 구간)을 수면(Sleepable) 가능한 뮤텍스로 교체함으로써, 커널의 99% 구간을 '선점 가능(Preemptible)' 구역으로 바꿔 데드라인을 반드시 준수하도록 튜닝한다.
  ┌──────────────────────────────────────────────────────────────┐
  │       선점형 환경에서의 공유 데이터 갱신 오동작 시나리오     │
  ├──────────────────────────────────────────────────────────────┤
  │                                                              │
  │   [공유 변수: 잔액(Balance) = 100]                           │
  │                                                              │
  │   프로세스 A (50 입금)         │ 프로세스 B (30 출금)        │
  │   -------------------------- │ -----------------------       │
  │   1. Reg1 = Balance (100)    │                               │
  │   2. Reg1 = Reg1 + 50 (150)  │                               │
  │   ==== 💥 타이머 인터럽트로 강제 선점 (Context Switch) ====  │
  │                              │ 1. Reg2 = Balance (100)       │
  │                              │ 2. Reg2 = Reg2 - 30(70)       │
  │                              │ 3. Balance = Reg2 (70)        │
  │   ==== 💥 프로세스 B 종료 및 프로세스 A 다시 CPU 점유 ====   │
  │   3. Balance = Reg1 (150)    │                               │
  │                                                              │
  │  🚨 최종 결과: Balance는 120이 되어야 하나, 150으로 덮어써짐.│
  │     (B의 30 출금 내역이 허공으로 증발하는 무결성 붕괴 발생)  │
  └──────────────────────────────────────────────────────────────┘

[다이어그램 해설] 선점형 스케줄링의 가장 큰 아킬레스건을 보여준다. 비선점이었다면 A가 1~3번을 다 끝내고 150이 된 상태에서 B가 진입하여 120으로 정상 종료되었을 것이다. 언제든 내가 쫓겨날 수 있다는 선점형 OS의 근본 가정 때문에, 개발자는 데이터의 원자성(Atomicity)을 보장하기 위해 락(Lock)을 남발하게 되고 이는 멀티코어 환경의 병목(Bottleneck)으로 직결된다. 빠름(선점)을 얻은 대신 안전(동기화)의 비용을 치르게 된 것이다.

  • 📢 섹션 요약 비유: 수술실에서 의사가 메스를 대고 있는 찰나에 교대 시간이 되었다고 다른 의사로 강제 교체되면 환자(데이터)가 죽습니다. 교체하더라도 "봉합"과 "인계"가 확실히 보장되는 자물쇠 메커니즘(Lock)이 없이는 선점형 제도를 쓸 수 없습니다.

Ⅴ. 기대효과 및 결론 (Future & Standard)

기대효과

강력한 선점 메커니즘은 특정 프로세스의 자원 독점을 원천 봉쇄함으로써, 마우스의 움직임과 키보드 타이핑이 끊기지 않는 매끄러운 사용자 경험 (UX)을 제공하며, 수백 개의 서버 데몬이 공정하게 동시에 실행되는 웹 생태계를 가능하게 만들었다.

결론 및 미래 전망

미래의 스케줄링은 "언제 선점할 것인가"의 예술로 발전하고 있다. 잦은 선점은 캐시 효율을 박살 내므로, 최근 리눅스 스케줄러(CFS)는 가상 실행 시간(vruntime)을 기반으로 문맥 교환 비용을 최소화하면서도 완벽한 공정성을 수학적으로 보장하려 노력한다. 나아가, 틱리스 커널(Tickless Kernel) 기술을 통해 주기적인 타이머 인터럽트의 전력 소모를 없애고 이벤트가 있을 때만 동적으로 인터럽트를 예약하여 모바일 기기의 배터리 수명을 극대화하는 방향으로 진화하고 있다.

  • 📢 섹션 요약 비유: 과거에는 기계적으로 10분마다 알람을 울려 강제로 교대시켰지만(Tick 기반), 이제는 학생들의 과제 진척도(vruntime)와 남은 체력(배터리)을 실시간으로 계산해 가장 최적의 타이밍에만 부드럽게 바통 터치를 지시하는 AI 지휘자로 발전하고 있습니다.

📌 관련 개념 맵 (Knowledge Graph)

개념 명칭관계 및 시너지 설명
타이머 인터럽트 (Timer Interrupt)선점형 스케줄링을 물리적으로 가능하게 하는 하드웨어 심장 박동으로, 이 신호가 커널의 스케줄러를 능동적으로 깨운다.
경쟁 조건 (Race Condition)언제든 선점당할 수 있다는 특성 때문에, 공유 자원에 접근할 때 타이밍에 따라 결과가 뒤틀리는 소프트웨어 최대의 위협이다.
임계 구역 (Critical Section)선점되더라도 데이터가 깨지지 않게 하기 위해 다중 프로세스가 동시에 진입하지 못하도록 락으로 감싸 보호해야 하는 코드 영역이다.
선점형 커널 (Preemptive Kernel)사용자 모드뿐만 아니라 커널 코드 수행 중에도 높은 우선순위 태스크가 개입할 수 있게 하여 실시간(RTOS) 응답성을 끌어올린 커널 아키텍처다.
라운드 로빈 (Round Robin)각 프로세스에 동일한 시간 할당량(Quantum)을 주고, 시간이 지나면 무조건 선점하여 큐의 맨 뒤로 돌려보내는 가장 대표적인 선점형 알고리즘이다.

👶 어린이를 위한 3줄 비유 설명

  1. 오락실 기계(CPU)에서 한 아이가 너무 게임을 잘해서 절대 안 죽고 10시간째 혼자 하고 있으면 뒷사람들은 화가 나겠죠?
  2. 선점형 스케줄링은 오락실 기계에 타이머를 달아서, "500원에 10분!" 시간이 지나면 화면이 탁 꺼지고 다음 친구에게 순서가 강제로 넘어가게 하는 마법의 규칙이에요.
  3. 이렇게 하면 아주 조금씩 번갈아 가며 게임을 하기 때문에, 모든 친구들이 지루하게 기다리지 않고 다 같이 즐겁게 놀 수 있답니다!