QNX RTOS: 4-6. Threads - Operations

2025. 11. 26. 17:31운영체제/QNX

스레드를 생성(pthread_create)한 이후, 런타임에 수행할 수 있는 다양한 조작법과 종료 전략을 정리함.

1. 스레드 종료와 뒷정리 (Termination & Join)

1.1. 종료 방법

스레드가 스스로 생을 마감하는 방법은 두 가지임.

  1. pthread_exit(value) 호출: 즉시 종료하며 value를 남김.
  2. 함수 리턴: 스레드 메인 함수에서 return value를 함. (내부적으로 pthread_exit이 호출됨)

1.2. pthread_join(): 기다림의 미학

  • 역할: 특정 스레드가 종료될 때까지 블로킹(Block)하며 기다림. 종료 시 남긴 반환값(void*)을 받아옴.
  • 관계: 프로세스(waitpid)와 달리 부모-자식 관계가 없음. 프로세스 내의 어떤 스레드든 다른 스레드를 Join 할 수 있음.
  • 주의: 이미 Join 된 스레드를 또 Join 하면 에러 발생. (Join은 한 번만 가능)

1.3. pthread_detach(): 쿨하게 보내주기

  • 기본 동작: 스레드는 종료되어도 누군가 join 해주기 전까지는 종료 상태 정보(좀비와 유사)를 유지하며 자원을 일부 점유함.
  • Detach: "난 얘 반환값 필요 없고, 죽으면 알아서 사라지게 해줘"라고 설정하는 것.
  • 특징: OS가 종료 즉시 모든 자원을 자동 회수함. 절대 좀비가 되지 않음. 단, join이 불가능해짐.

2. 스레드 식별과 제어 (Identification & Control)

2.1. 식별 (Identity)

  • pthread_self(): 자기 자신의 Thread ID를 반환함.
  • QNX 특화 기능: QNX API에서는 Thread ID 자리에 0을 넣으면 "나 자신(Calling Thread)"을 의미함. (ID가 1부터 시작하므로 충돌 없음)

2.2. 이름 짓기 (pthread_setname_np())

  • 임베디드 디버깅의 핵심임. pidin이나 디버거에서 봤을 때 "Thread 1, 2, 3"으로 뜨면 뭐가 뭔지 모름.
  • 이 함수로 "CAN_Rx", "Logger" 같이 이름을 붙여주면 시스템 분석이 매우 쉬워짐.

2.3. 스케줄링 변경 (pthread_setschedparam())

  • 실행 중에 스레드의 우선순위나 정책(FIFO, RR)을 바꿀 수 있음.
  • 예: 평소엔 낮은 우선순위로 돌다가, 긴급 이벤트 발생 시 스스로 우선순위를 높여서 처리하는 식의 구현이 가능함.

3. 스레드 종료 전략 (Termination Strategy)

RTOS에서 가장 중요한 파트임. 스레드를 외부에서 강제로 죽이는 건 매우 위험함.

3.1. pthread_kill()의 오해

  • 이름이 kill이라서 스레드를 죽이는 함수 같지만, 실제로는 "시그널을 보내는 함수"임.
  • 시그널을 보냈는데 해당 스레드가 무시(Ignore)하거나 블록(Block)하고 있으면 아무 일도 안 일어남.
  • 만약 처리되지 않은 시그널이 발생하면? 프로세스 전체가 죽어버림. (주의 요망)

3.2. pthread_cancel(): 비동기 종료

  • POSIX 표준 방식이지만, 비동기적(Asynchronous)이라 위험함.
  • 스레드가 리소스(뮤텍스 잠금, 메모리 할당)를 잡고 있는 도중에 캔슬당하면, 자원 해제가 안 된 상태로 죽어버림 -> Deadlock이나 Memory Leak 원인.

3.3. Best Practice: 동기적 자진 종료 (Synchronous Termination)

가장 권장되는 방식은 스레드가 스스로 "죽어야 할 때"를 인지하고 정리 후 죽는 것임.

  1. Flag Check Loop: 스레드 메인 루프에 while(!done) 같은 조건을 둠.
  2. Notification: 종료시키고 싶은 쪽에서 done = 1로 만들고 시그널/이벤트로 깨움.
  3. Cleanup & Exit: 스레드가 루프를 탈출하면서 mutex_unlock, free, close 등을 깔끔하게 수행하고 리턴함.

4. 자원 정리 (Cleanup)

스레드가 종료될 때 정리해야 할 것들:

  • 동기화 객체: 잠가둔 뮤텍스(Mutex), RWLock 등 해제.
  • 메모리: malloc 한 힙 메모리 해제.
  • 핸들: 오픈한 파일, 소켓, 메시지 큐 닫기.
  • 스택(Stack): 스레드 스택은 OS가 자동으로 회수함. (단, Main 스레드의 스택은 프로세스 종료 전까지 유지됨)

 

 

 


💡 요약 및 인사이트

  1. 강제 종료 금지: pthread_cancel이나 외부 킬은 자원 누수(Leak)와 데드락의 지름길임. 무조건 플래그를 보고 스스로 죽게 설계해야 함.
  2. 이름 붙이기: pthread_setname_np()는 선택이 아니라 필수라고 생각. 나중에 pidin 쳤을 때 스레드 10개가 이름 없이 떠 있으면 분석 불가능함.
  3. Detach 활용: 반환값이 필요 없는 "Fire-and-Forget" 작업(예: 로그 저장, 단순 이벤트 처리)은 pthread_detach를 써서 리소스를 바로바로 반납하게 하는 게 좋음.