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 프로세스) 내부의 스레드 스케줄러에게 엄청난 나비효과를 불러일으킨다.
- 파싱과 인터셉트(Intercept): NSH 셸 파서는 문자열 끝에 붙은
&기호를 발견하는 즉시 이를argv배열에 포함시키지 않고 낚아챈다. (즉, 여러분의custom_app_main함수는 이&기호의 존재를 평생 모른다.) - 비동기 스폰(Asynchronous Spawn): 셸 커널은
custom_app_main함수의 주소를 스레드 생성 API(task_spawn)에 던져놓고, 이 함수의 처리가 완료될 때까지 기다리지(Blocking) 않는다. - 프롬프트 복귀: 커널은 즉시 하던 일을 멈추고
pxh>프롬프트를 화면에 다시 띄워, 사용자의 다음 키보드 입력을 받을 채비를 한다.
그 결과, custom_app 모듈은 메인 런루프를 돌며 자기가 할 일을 백그라운드(Background) 스레드에서 조용히 수행하고, 여러분은 동일한 터미널 창에서 곧바로 ekf2 status나 commander arm 같은 다른 명령어를 칠 수 있게 된다.
2. 생존 신고: 프로세스 ID (PID)의 반환
백그라운드로 쫓겨난 스레드들은 시야에서 사라졌을 뿐, RAM 한구석에서 맹렬하게 살아서 움직이고 있다. 셸은 스레드를 허공에 던져버리기 전, 이 스레드의 목줄표인 **프로세스 ID (PID: Process ID)**를 우리에게 친절하게 하나 툭 던져준다.
명령어를 실행하자마자 다음과 같이 대괄호에 싸인 숫자가 한 줄 찍힌다면 백그라운드 실행이 완벽하게 성공한 것이다.
[1] 145
여기서 145가 바로 custom_app 스레드에 부여된 고유 식별자(PID)이다. (대괄호 안의 1은 현재 셸 세션에서 백그라운드로 돌린 작업의 순번 번호(Job ID)를 의미한다.)
2.1 좀비 확인 사살 기법
터미널에서 보이지 않는다고 모듈이 평화롭게 살고 있다는 보장은 없다. 널 포인터 에러가 나서 혼자 조용히 죽어버렸을 수도 있고, 무한 블로킹 I/O에 걸려 식물인간이 되어버렸을 수도 있다.
우리는 이 PID 번호표를 들고 두 가지 NSH 기본 내장 명령어를 통해 모듈의 생사를 실시간으로 추궁할 수 있다.
ps(Process Status): 터미널에ps를 치면 현재 구동 중인 모든 데몬들의 목록이 뜬다. 여기서 PID145번이 지닌 스레드 상태 플래그가READY인지WAIT인지, 그리고 남은 스택 여유 공간(Stack Margin)이 얼마나 되는지 현미경처럼 들여다볼 수 있다.kill: 모듈이 폭주하여 CPU를 갉아먹고 있다면 지체 없이kill 145를 입력하여 커널 레벨에서 스레드의 모가지를 잘라버릴 수 있다. (단, PX4는 안정성을 위해 무식한kill명령어보다는 모듈 내부 로직으로 구현된custom_app stop을 통한 그레이스풀 셧다운(Graceful Shutdown)을 강력히 권장한다.)
이제 커스텀 모듈이 백그라운드 제어권까지 우아하게 확보하는 법을 완벽히 마스터했다. 하지만 지금까지 우리가 상상해 온 메인 함수와 무한 루프는 사실 C 언어 스타일의 매우 투박한 프로시저(Procedure)일 뿐이다.
수백 개의 센서와 수천 개의 파라미터를 우아하게 관리하려면 진짜 ‘객체지향(Object-Oriented)’ 시스템이 필요하다. 다음 장(21.4)에서는 PX4 코어 개발자들이 깎아놓은 최고의 걸작인 ModuleBase 템플릿 기반 표준 모듈 아키텍처를 본격적으로 이식해 보자.