# 1. 자원 동기화 및 메모리 관리 체계
플랫(Flat) 메모리 주소 모델을 기반으로 하는 단일 운영체제 공간 내에서, 수십 개의 태스크(Task)와 스레드(Thread)가 동시에 돌아간다는 것은 곧 ’지옥문이 항상 열려 있음’을 뜻한다. A 모듈과 B 모듈이 동시에 같은 센서 배열 메모리에 글씨를 쓰려고 덤벼들면 데이터가 박살 나버리기 때문이다 (Race Condition). 이를 막기 위한 커널 레벨의 동기화(Synchronization) 기법과 메모리 철학을 뜯어본다.
무결성의 방패: 뮤텍스(Mutex) 와 세마포어(Semaphore)
NuttX와 PX4 생태계 내부에서는 공유 자원(Shared Resource)을 건드릴 때 절대 맨손으로 만지지 않는다. 반드시 자물쇠(Lock)를 채우는 의식이 강제된다.
- 뮤텍스 (
pthread_mutex_lock): 상호 배제(Mutual Exclusion)의 꽃이다. 예를 들어 I2C 버스를 통해 나침반 센서값을 읽어오려면 버스를 점유해야 한다. 이때 한 스레드가 뮤텍스 자물쇠를 걸어 잠그면, 뒤늦게 I2C 버스를 쓰려고 접근한 다른 스레드들은 이 앞의 스레드가unlock으로 키를 반납할 때까지 그 자리에서 돌로 굳어져(Blocked/Sleep) 기다려야 한다. 이를 통해 물리 버스 통신의 엉킴을 완벽히 차단한다. - 우선순위 역전(Priority Inversion) 방지: 최하위 우선순위 로거가 뮤텍스를 쥐고 있는데, 최상위 우선순위 자세 제어기가 그 뮤텍스를 기다리다 못해 기체가 추락해 버리는 상황(우선순위 역전)을 막기 위해, NuttX 뮤텍스는 내부에 가속 부스터 철학이 박혀 있다. 로거가 쥐고 있는 자원을 최상급 스레드가 기다리게 되는 순간, 스케줄러는 일시적으로 비루한 로거 스레드의 우선순위를 최고 등급으로 강제 뻥튀기(Priority Inheritance) 시켜버린다. 빨리 일 끝내고 자물쇠를 풀게 하기 위함이다.
메모리(RAM) 관리 철학: 동적 할당의 저주
리눅스 개발자가 임베디드로 넘어와 가장 크게 저지르는 실죄가 바로 루프 내부에서 new 나 malloc() 을 남발하는 행위다.
NuttX 커널의 메인 힙(Heap) 공간은 대용량 서버와 달리 단 1~2MB 대역 쪼가리에 불과하다. 비행 중(In-Flight)에 수십만 번 new 와 delete 를 반복하면 필연적으로 메모리 힙 덩어리들 사이에 빈 구멍이 생기는 ’파편화(Fragmentation)’가 가속화된다. 어느 순간 커다란 행렬 구조체를 생성하려 할 때, 연속된 물리적 RAM 공간을 찾지 못해 커널이 알림봇(Out-of-Memory)을 띄우고 그 즉시 시스템을 하드 리부트(Reboot) 시켜버린다. 즉 비행 중인 드론이 하늘에서 꺼져버린다는 뜻이다.
따라서 PX4 코딩 세계에서 모든 거대 버퍼나 수학 매트릭스는 철저하게 스레드 시작 시점 전역 메모리 할당(.bss 섹션) 이나 정적 스택(Stack) 공간에 크기를 못 박아 선점하는(Static Allocation) 철학이 종교처럼 강제된다.