21.3.3.2. 백그라운드 실행 연산자(`&`)의 처리 로직 및 프로세스 ID(PID) 반환 확인

21.3.3.2. 백그라운드 실행 연산자(&)의 처리 로직 및 프로세스 ID(PID) 반환 확인

여러분이 뼈 빠지게 고생해서 커맨드라인 ਪาร์싱 로직(21.3.2)을 구현하고, SITL 터미널에 custom_app start 라고 입력하여 모듈을 런루프 속으로 밀어 넣었다고 가정해 보자.

그런데 터미널 창(NSH)의 커서가 다음 줄로 넘어가지 않고 그 자리에서 깜빡거리며 ’먹통’이 되어버렸다. pxh> 라는 프롬프트는 영영 돌아오지 않고, 여러분은 10초에 한 번씩 화면에 찍히는 PX4_INFO 로그만 멍하니 바라보고 있어야 한다. 여러분의 모듈 스레드가 터미널의 입력 포그라운드(Foreground) 제어권을 몽땅 독점해 버렸기 때문이다.

이러한 불상사를 막기 위해, 리눅스 bash 셸과 마찬가지로 NSH 콘솔 역시 아주 유연한 **백그라운드 실행 연산자(&)**를 기본적으로 지원한다.

1. 앰퍼샌드(&)의 마법: 제어권의 반환

명령어의 맨 끝에 스페이스를 띄우고 & 기호를 하나 붙여 보자.

pxh> custom_app start &

이 단 한 글자의 기호는 픽스호크 펌웨어(혹은 SITL의 px4 프로세스) 내부의 스레드 스케줄러에게 엄청난 나비효과를 불러일으킨다.

  1. 파싱과 인터셉트(Intercept): NSH 셸 파서는 문자열 끝에 붙은 & 기호를 발견하는 즉시 이를 argv 배열에 포함시키지 않고 낚아챈다. (즉, 여러분의 custom_app_main 함수는 이 & 기호의 존재를 평생 모른다.)
  2. 비동기 스폰(Asynchronous Spawn): 셸 커널은 custom_app_main 함수의 주소를 스레드 생성 API(task_spawn)에 던져놓고, 이 함수의 처리가 완료될 때까지 기다리지(Blocking) 않는다.
  3. 프롬프트 복귀: 커널은 즉시 하던 일을 멈추고 pxh> 프롬프트를 화면에 다시 띄워, 사용자의 다음 키보드 입력을 받을 채비를 한다.

그 결과, custom_app 모듈은 메인 런루프를 돌며 자기가 할 일을 백그라운드(Background) 스레드에서 조용히 수행하고, 여러분은 동일한 터미널 창에서 곧바로 ekf2 statuscommander arm 같은 다른 명령어를 칠 수 있게 된다.

2. 생존 신고: 프로세스 ID (PID)의 반환

백그라운드로 쫓겨난 스레드들은 시야에서 사라졌을 뿐, RAM 한구석에서 맹렬하게 살아서 움직이고 있다. 셸은 스레드를 허공에 던져버리기 전, 이 스레드의 목줄표인 **프로세스 ID (PID: Process ID)**를 우리에게 친절하게 하나 툭 던져준다.

명령어를 실행하자마자 다음과 같이 대괄호에 싸인 숫자가 한 줄 찍힌다면 백그라운드 실행이 완벽하게 성공한 것이다.

[1] 145

여기서 145가 바로 custom_app 스레드에 부여된 고유 식별자(PID)이다. (대괄호 안의 1은 현재 셸 세션에서 백그라운드로 돌린 작업의 순번 번호(Job ID)를 의미한다.)

2.1 좀비 확인 사살 기법

터미널에서 보이지 않는다고 모듈이 평화롭게 살고 있다는 보장은 없다. 널 포인터 에러가 나서 혼자 조용히 죽어버렸을 수도 있고, 무한 블로킹 I/O에 걸려 식물인간이 되어버렸을 수도 있다.

우리는 이 PID 번호표를 들고 두 가지 NSH 기본 내장 명령어를 통해 모듈의 생사를 실시간으로 추궁할 수 있다.

  1. ps (Process Status): 터미널에 ps를 치면 현재 구동 중인 모든 데몬들의 목록이 뜬다. 여기서 PID 145번이 지닌 스레드 상태 플래그가 READY 인지 WAIT 인지, 그리고 남은 스택 여유 공간(Stack Margin)이 얼마나 되는지 현미경처럼 들여다볼 수 있다.
  2. kill: 모듈이 폭주하여 CPU를 갉아먹고 있다면 지체 없이 kill 145 를 입력하여 커널 레벨에서 스레드의 모가지를 잘라버릴 수 있다. (단, PX4는 안정성을 위해 무식한 kill 명령어보다는 모듈 내부 로직으로 구현된 custom_app stop 을 통한 그레이스풀 셧다운(Graceful Shutdown)을 강력히 권장한다.)

이제 커스텀 모듈이 백그라운드 제어권까지 우아하게 확보하는 법을 완벽히 마스터했다. 하지만 지금까지 우리가 상상해 온 메인 함수와 무한 루프는 사실 C 언어 스타일의 매우 투박한 프로시저(Procedure)일 뿐이다.
수백 개의 센서와 수천 개의 파라미터를 우아하게 관리하려면 진짜 ‘객체지향(Object-Oriented)’ 시스템이 필요하다. 다음 장(21.4)에서는 PX4 코어 개발자들이 깎아놓은 최고의 걸작인 ModuleBase 템플릿 기반 표준 모듈 아키텍처를 본격적으로 이식해 보자.