QNX RTOS: 4-2. Processes - Creation

2025. 11. 26. 14:48운영체제/QNX

프로세스를 만드는 방법은 크게 세 가지 호출(Call)로 나뉨.

  1. fork(): 복제 (Clone). 부모를 그대로 베낌.
  2. exec(): 교체 (Replacement). 현재 프로세스를 새로운 프로그램으로 덮어씀.
  3. posix_spawn(): 탄생 (Creation). 새로운 프로그램을 바로 실행함.

1. fork(): 부모의 완벽한 복제

fork()는 호출하는 순간, 부모 프로세스와 똑같은 복사본(자식)을 만들어냄.

  • 동작 흐름:
    • 부모가 fork()를 호출하면 자식이 생성됨.
    • 반환값(Return Value): 이게 중요함. 부모에게는 자식의 PID(>0)를, 자식에게는 0을 반환함. 이 값을 보고 코드 내에서 "나는 부모구나", "나는 자식이구나"를 판단해 분기함.

  • 상속받는 것 (Inheritance):
    • 데이터 세그먼트 (변수 등 메모리 영역)
    • 파일 디스크립터 (Open된 파일들)
    • 스레드 속성 (우선순위, 스케줄링 알고리즘, 시그널 마스크 등)
    • 보안 속성 (UID, GID)
  • 상속받지 않는 것:
    • 타이머, 채널 연결(Connection ID) 같은 리소스.

⚠️ 치명적인 단점: 멀티스레드 환경

임베디드 개발자가 fork()를 기피해야 하는 이유임.

  • 부모 프로세스가 멀티스레드(Thread A, Thread B)라고 가정해 보자.
  • Thread A가 fork()를 호출하는 순간, Thread B가 메모리 데이터를 수정 중이었다면?
  • 자식 프로세스는 데이터가 꼬인 상태(Inconsistent state)로 복제될 수 있음.
  • 더 무서운 건, 자식 프로세스는 오직 fork()를 호출한 스레드 하나만 가지고 태어남. 나머지 스레드는 증발함. 이로 인해 뮤텍스(Mutex) 잠금 상태 등이 꼬여서 데드락이 걸릴 확률이 매우 높음.

2. exec(): 뇌 이식 수술

exec() 계열 함수(execl, execv 등)는 프로세스를 새로 만드는 게 아님. 현재 프로세스의 껍데기(PID, 프로세스 테이블 엔트리)는 유지하되, 내용물(코드, 데이터)을 새로운 프로그램으로 싹 갈아치우는 것임.

  • 특징:
    • PID가 바뀌지 않음.
    • 호출이 성공하면 리턴하지 않음. (이미 다른 프로그램이 되었으니까)
    • 데이터 세그먼트는 완전히 새로운 프로그램의 것으로 초기화됨.
  • 상속:
    • 파일 디스크립터는 그대로 물려받음. (단, FD_CLOEXEC 플래그를 켜면 exec 수행 시 닫힘)

3. posix_spawn(): QNX의 표준이자 권장 사항

posix_spawn()은 "이 프로그램 실행해줘"라고 Process Manager에게 직접 요청하는 함수임.

  • 동작: 새로운 프로그램을 메모리에 로드하고 실행함.
  • 특징:
    • POSIX 표준 함수임. (이식성 좋음)
    • 복잡한 파라미터 구조체를 통해 파일 디스크립터 제어, 시그널 마스크 설정 등을 정밀하게 할 수 있음.
    • 편의를 위해 spawn() 같은 비표준 함수도 있지만, 표준인 posix_spawn() 사용을 권장함.

4. 왜 posix_spawn()을 써야 하는가? (vs fork+exec)

전통적인 유닉스 방식(Old School)은 fork()로 복제한 뒤, 자식 프로세스가 exec()을 호출해 변신하는 방식이었음. 하지만 QNX에서는 이 방식이 비효율적임.

4.1. 효율성 (Efficiency)

  • fork + exec:
    1. fork(): 부모의 주소 공간을 복사함. (Copy)
    2. exec(): 복사한 걸 바로 다 지우고 새 프로그램을 로드함. (Destroy & Load)
    3. 결과적으로 중간에 만든 복사본은 쓰지도 않고 버려짐. 낭비임.
  • posix_spawn:
    • 내부적으로 fork + exec를 하는 게 아님.
    • Process Manager에게 "이거 실행해"라는 메시지 한 방을 보냄.
    • 데이터 복사 과정이 아예 없음. 훨씬 빠르고 가벼움.

4.2. 안전성 (Safety)

  • 앞서 말했듯 멀티스레드 환경에서 fork()는 시한폭탄임.
  • posix_spawn()은 부모의 메모리 상태를 복제하지 않고, 깨끗한 상태에서 새 프로세스를 띄우므로 스레드 동기화 문제에서 자유로움.

💡 요약 및 실무 가이드

  1. 3가지 방법: fork(복제), exec(교체), posix_spawn(생성).
  2. fork의 위험성: 멀티스레드 프로그램에서는 데이터 불일치와 데드락 위험 때문에 사용을 피해야 함.
  3. QNX의 정석: posix_spawn()을 써라.
    • Process Manager와 직접 통신하여 메시지 한 번으로 프로세스를 생성함.
    • 데이터 복사 비용이 없어 빠르고(Efficient), 스레드 문제로부터 안전함(Safe).

'운영체제 > QNX' 카테고리의 다른 글

QNX RTOS: 4-4. Thread  (0) 2025.11.26
QNX RTOS: 4-3. Processes - Detecting Termination  (0) 2025.11.26
QNX RTOS: 4-1. Processes and Threads  (0) 2025.11.26
QNX RTOS: 3. Security Policies  (0) 2025.11.26
QNX RTOS: 2-1. Running and Debugging  (0) 2025.11.26