## 0.1 스핀(spin) 함수 계층 동기식 대기 집합(WaitSet) 블로킹 역학
ROS2 클라이언트 라이브러리 애플리케이션의 런타임 수명을 주도하는 가장 핵심적인 진입점은 rclcpp::spin() (C++) 및 rclpy.spin() (Python) 함수이다. 개발자가 노드 객체를 이그제큐터(Executor) 공간에 인계하고 이 함수를 호출하는 순간, 메인 스레드는 즉각적으로 무한루프 형태의 이벤트 대기(Event Waiting) 상태로 진입하게 된다. 이 현상을 구동하는 기저의 시스템 프로그래밍적 원리가 바로 동기식 랑데부(Synchronous Rendezvous) 기법에 입각한 대기 집합(WaitSet) 블로킹 역학이다.
0.1.1 대기 집합(WaitSet)의 메모리 구성 타당성
spin()이 호출되면 이그제큐터는 등록된 모든 노드를 순회하며 활성화된 서브스크립션, 서비스 서버, 액션 서버, 그리고 타이머 인터페이스 객체들의 포인터를 수집한다. 이 포인터들의 배열 집합은 RCL(ROS Client Library) 계층에서 한데 묶여 단일 rcl_wait_set_t C 구조체로 메모리에 압축 적재된다.
대기 집합을 개별적으로 운영하지 않고 하나의 커다란 구조체 트리로 병합하는 이유는, 분산된 파일 디스크립터(File Descriptor)나 커널 타이머 이벤트를 감시하기 위해 운영체제(OS)로의 컨텍스트 스위칭(Context Switching) 연산 횟수를 최소화하기 위함이다. 즉, 시스템 상에 존재하는 수십 개의 통신 엔티티의 이벤트를 단 한 번의 OS 커널 인터럽트를 통해 모니터링하기 위한 고성능 네트워크 프로그래밍의 표준 폴링(Polling) 패턴을 프레임워크 차원에서 구조화한 것이다.
0.1.2 rcl_wait 함수의 동기식 스레드 블로킹(Blocking) 메커니즘
이그제큐터는 구성된 rcl_wait_set_t를 매개변수로 하여 rcl_wait() 함수를 실행시킨다. 이 함수는 논블로킹(Non-blocking) 비동기 호출이 아닌, 스레드의 실행 흐름을 완전히 차단하는 동기식 블로킹(Synchronous Blocking) 인터페이스이다.
rcl_wait() 내부로 전이된 제어권은 다시금 RMW(ROS Middleware) 계층을 통해 통신 프로토콜 구현체(예: eProsima Fast DDS 등)로 이관되며, 최종적으로는 POSIX 표준의 poll(), epoll() 혹은 조건 변수(Condition Variable)와 같은 커널 락(Kernel Lock) 시스템 큐에 스레드를 수면(Sleep) 상태로 던져넣는다. 이러한 블로킹 체계는 CPU의 스핀 루프 통전(Spin-loop Polling)에 의한 자원 고갈(100% CPU Occupation)을 방지하고, 메인 프로세서의 사이클을 로봇의 영상 처리 등 다른 연산 집약적 태스크에 온전히 양도하도록 보장한다.
0.1.3 인터럽트 기반의 비동기적 동면 해제(Wake-up)와 콜백 반환
스레드가 블로킹된 상태에서, 드론의 센서 노드로부터 무선 데이터그램(Datagram)이 네트워크 소켓에 도착하거나, 사전에 계산된 타이머 주기가 만료되어 하드웨어 인터럽트가 발생하면 운영체제의 커널은 수면 중인 스레드를 깨운다(Wake-up).
블로킹이 해제되어 rcl_wait()가 반환(Return)될 때, 해당 함수는 단순히 제어권만을 돌려주지 않고 대기 집합(WaitSet) 구조체 내부의 어떤 엔티티가 동면 해제의 트리거(Trigger) 구실을 했는지에 대한 마스킹(Masking) 정보를 함께 반환한다. 이그제큐터는 반환된 마스크 플래그를 해석하여 이벤트를 수신한 객체를 특정하고, 이 객체에 바인딩된 사용자 정의 콜백(Callback) 함수를 큐에서 추출하여 실행 메모리 상에 즉각 디스패치(Dispatch)하게 된다. 결국 spin()의 무한 루프는 ’대기 집합 구성 -> 스레드 블로킹 대기 -> 이벤트 동면 해제 -> 콜백 디스패치’라는 네 박자 사이클을 프로세스가 종료될 때까지 무한정 반복하는 이벤트 거버넌스 엔진이다.