본문 바로가기
게임 데이터 가이드

입력 파이프라인의 멀티스레드 분리, 이벤트 큐 우선 처리, 동시성 관리

by oneplay1 2025. 10. 22.
입력 파이프라인은 엔진의 반응성을 결정짓는 핵심 구조다. 키보드·마우스·패드에서 들어오는 이벤트를 실시간으로 처리하면서, 렌더링·물리 계산과의 동기화를 유지해야 한다. 본문은 입력 파이프라인의 멀티스레드 분리 구조, 이벤트 큐 우선 처리 방식, 동시성 관리 전략을 다룬다. 모든 설명은 실제 엔진 수준의 설계 원리를 기반으로 하고, SVG 다이어그램으로 구조를 시각화했다.

입력 파이프라인의 병렬화와 구조적 분리

게임 엔진의 입력 파이프라인(Input Pipeline)은 단순히 키 이벤트를 수집하는 수준이 아니라, 입력 이벤트의 발생·처리·소비를 프레임 단위로 정렬하는 복합 시스템이다. 일반적으로 입력 처리는 메인 스레드(Main Thread)에서 이루어지지만, 현대 엔진에서는 렌더링·물리·AI가 모두 병렬화되어 있어, 단일 스레드 입력 구조는 병목의 원인이 된다.

이를 해결하기 위해 도입된 것이 입력 스레드(Input Thread)의 분리다. 이 스레드는 OS 레벨의 이벤트 큐(예: Windows Raw Input, Linux XInput)를 직접 수신하고, 자체 버퍼로 복제한 후 게임 로직 스레드로 비동기 전송한다. 즉, 입력을 메인 프레임보다 “앞서” 처리하는 방식이다. 이 구조를 사용하면 입력 반응 속도를 30~40% 단축할 수 있다.

그러나 입력을 병렬로 처리할 경우, 각 스레드 간 데이터 불일치가 발생할 수 있다. 예를 들어 캐릭터 이동 키가 눌린 상태를 물리 스레드가 읽었을 때, 아직 렌더 스레드에는 반영되지 않았을 수 있다. 이를 방지하기 위해 “입력 스냅샷(Input Snapshot)” 구조를 사용한다. 입력 스레드는 매 프레임마다 동일한 시점의 스냅샷을 생성하고, 모든 서브시스템이 이 데이터를 참조하도록 동기화한다.

이벤트 큐 우선 처리와 실시간 스케줄링

입력 이벤트는 일반적으로 큐(queue) 형태로 관리된다. 키 입력, 마우스 이동, 패드 축 조작 등은 서로 다른 우선순위를 가진다. 예를 들어 ‘이동’은 지속 이벤트이지만, ‘공격’은 즉시 반응해야 하는 단일 이벤트다. 이러한 성격 차이를 반영하기 위해, 엔진은 우선 큐(Priority Queue) 방식을 사용한다.

우선 큐는 입력 이벤트를 단순 FIFO 순서가 아니라 중요도 기반으로 처리한다. 중요도는 이벤트의 “대기 시간 허용치”로 정의된다. 예를 들어 공격 키의 허용 지연이 4ms, 이동 키가 16ms라면, 스케줄러는 공격 이벤트를 먼저 소비한다. 이 과정은 입력 스레드 내부에서 수행되며, 메인 스레드에 전달되기 전 정렬된다.

큐의 처리 주기는 일반적으로 1프레임보다 짧다. 렌더 프레임이 16.67ms일 때, 입력 큐는 약 2~3ms 단위로 갱신된다. 이렇게 하면 입력 누락 없이 정밀한 타이밍을 유지할 수 있다. 또한, 입력 스레드는 “하드웨어 타임스탬프”를 활용해 실제 입력 시각을 기록한다. 이는 프레임이 약간 늦더라도 입력의 실시간성을 보정하는 역할을 한다.

입력 이벤트 큐 구조 하드웨어 입력 이벤트 큐 우선 정렬 게임 로직
하드웨어 → 큐 → 정렬 → 로직 순으로 이벤트가 전달된다.

입력 큐는 단순히 데이터를 저장하는 용도가 아니라, 동시성 제어의 중심 역할을 한다. 하나의 입력 이벤트가 여러 서브시스템(예: 카메라, UI, 캐릭터 컨트롤)에 전달되기 때문이다. 이를 위해 큐는 이벤트 ID를 중심으로 한 “멀티캐스트(multicast)” 구조를 가진다. 하나의 입력이 여러 수신자에게 복제되지만, 동일 프레임 내에서는 한 번만 소비되도록 타임스탬프 기반 제어를 수행한다.

동시성 관리와 입력-렌더 일관성 유지

동시성 관리(Concurrency Management)는 여러 입력 스레드가 동시에 작동할 때 충돌을 방지하는 시스템이다. 입력, 물리, 렌더, UI 등 각 서브시스템이 같은 입력 데이터를 다른 타이밍에 읽을 경우, 동기화 지점이 중요하다. 이를 해결하기 위해 락 프리(lock-free) 큐가 사용된다. 입력 스레드는 이벤트를 Atomic Push로 삽입하고, 소비 스레드는 Atomic Pop으로 제거한다. 이렇게 하면 락 경합이 없으면서도 안전한 병렬 접근이 가능하다.

한편, 렌더링과 입력의 동기화를 위해 “입력 프레임 넘버링(Input Frame Index)”이 사용된다. 모든 입력은 고유한 프레임 인덱스를 가지며, 렌더 스레드는 동일 인덱스의 입력만 참조한다. 이를 통해 프레임 지연이나 입력 선행 현상이 발생하지 않는다.

마지막으로, 입력 처리에서 중요한 것은 “지연 안정성(latency stability)”이다. 절대적인 지연보다 일관된 지연이 플레이어에게 더 자연스러운 체감을 준다. 따라서 스케줄러는 CPU 점유율이나 I/O 부하에 따라 입력 큐 주기를 자동 조정한다. 이로써 프레임이 불규칙하더라도 입력 반응이 안정적으로 유지된다.

입력 멀티스레드 분리 구조 Input Thread Logic Thread Render Thread
입력, 로직, 렌더 스레드가 분리되어 독립적으로 작동하되, 동기화 시점에서 일관성을 유지한다.
입력 동시성 제어 흐름 입력 수집 큐 정렬 락 프리 전송 프레임 동기화
입력 수집 → 큐 정렬 → 락 프리 전송 → 동기화 단계를 순환한다.