19.5. 구독자(Subscriber) 구현: 이벤트 대기(Wait/Poll) 및 콜백 방식

19.5. 구독자(Subscriber) 구현: 이벤트 대기(Wait/Poll) 및 콜백 방식

이전 19.4의 수많은 험난한 단원들에서 철저히 다루었던 px4_usleep() 기반의 ‘수동적인’ 폴링(Polling) 및 업데이트 체크 아키텍처는 분명 수문장을 세워 거대한 메모리 최적화를 이루어냈지만, 커널 시스템 아키텍처 관점에서는 태생적으로 어쩔 수 없는 치명적인 ‘눈 뜬 장님(Blind Spot)’ 시간을 스레드 수면 주기로서 영원히 가지게 된다.
다시 말해, 내 데몬 스레드가 0.2초짜리 꿀잠(usleep)을 자고 있는 바로 그 통제 불능의 찰나 동안 무더기로 쏟아져 들어온 초고정밀 EKF 항법 데이터들은, 내 스레드가 스케줄러의 타이머 알람을 듣고 아침에 기상할 때까지 픽스호크 미들웨어 링 버퍼망 안에서 짧게는 수십 밀리초, 길게는 수 초 동안 옴짝달싹 못한 채 차갑게 방치되며 무자비하고 피눈물 나는 제어 지연 시간(Latency)의 끔찍한 물리적 희생양이 되고 만다.

이러한 수동적 슬립 폴링 시스템의 근본적이고 필연적인 1차원적 기술 한계를 산산이 부수고, 가장 극한의 인터럽트(Interrupt) 기반 0.1ms 하드코어 실시간(Real-time) 비동기 반응성을 물리적으로 쟁취하기 위해, 우리는 이제 커널 레벨의 동기화 스케줄링 기법인 이벤트 대기(Wait/Poll) 및 콜백(Callback) C++ 아키텍처 심연으로 본격적으로 넘어가게 된다.

이 통합 단원에서는 내 가엾은 C++ 워커 스레드가 하드코딩된 무의미한 타이머 주기로 멍청하게 깨어나는 낡은 방식을 폭파해 버리고, 건너편 트랙의 퍼블리셔 데몬이 데이터를 VFS 버퍼 꼬리에 쏘는 바로 그 순간(Event), NuttX 커널이 직접 내 잠자는 스레드의 뺨을 후려쳐 강제로 깨우고 링 버퍼망으로 밀어 넣어버리는 두 가지 고도화된 스케줄링 수신 통제 전략을 파헤친다.

  • POSIX px4_poll() 커널 함수의 짐승 같은 반응성: 유닉스 커널 시스템 콜의 황제인 poll()을 픽스호크 OS 환경에 맞게 계승 래핑한 이 무식한 C API는, 내 무한 루프 스레드를 usleep이 아닌 poll 함수 내부에 쑤셔 넣어 영구 기절(Block)시켜 두었다가, 링 버퍼 메모리에 아주 작은 새 데이터가 단 한 방울(Byte)이라도 떨어지는 순간(File Descriptor Event) 하드웨어 인터럽트를 걸어 0.1ms 내에 가장 폭력적이고 빠르게 내 데몬을 깨워버린다. (19.5.1 단원 타설 통제)
  • C++ uORB::SubscriptionCallback의 가장 진보하고 우아한 모던 객체지향 아키텍처: 앞선의 더럽고 복잡한 C 포인터 스케줄링 API들을 모조리 캡슐화시켜 숨겨버린 뒤, VFS에 데이터가 들어왔을 때 오직 내 클래스 안에 은밀히 정의해둔 콜백 멤버 함수(메서드)만이 백그라운드 워크 큐(Work Queue) 스레드 풀 위에서 팝업처럼 자동 다중 실행되게 만드는, PX4에서 가장 비싸고 초호화의 런타임 C++ 모던 프레임워크 타설법을 꿰뚫어 본다. (19.5.2 단원 타설 통제)

어설픈 수작업 타이머 수면 시간에 얄팍하게 기대지 않고, 픽스호크 OS 스케줄러 자체의 뜨거운 심장 박동(Tick)에 당신의 C++ 코드를 직접 혈관처럼 직결시키는 이 핏빛 통제 기술을 마스터해야만, 당신이 설계한 모듈은 비로소 1000Hz가 넘어가는 가장 가혹한 드론 모터 이너 루프(Inner Loop) 제어 시스템 생태계의 실시간 패권을 완벽하게 장악할 수 있게 된다.