IT·리눅스/리눅스

프로세스 vs 스레드 - 리눅스의 PID, TID, PPID 한 번에 정리

jmineekim 2026. 6. 18. 10:00

운영 중에 "왜 ps에는 프로세스 하나로 보이는데 top에서는 스레드가 100개 떠 있죠?"라는 질문을 받은 적이 있습니다. 사실 저도 처음엔 PID, TID, PPID, LWP가 뭐가 다른지 헷갈렸어요. Java 애플리케이션 CPU 100% 잡다가 결국 스레드 단위로 봐야 한다는 걸 알게 됐죠. 오늘은 리눅스에서 프로세스와 스레드가 실제로 어떻게 구분되고, 명령어로 어떻게 들여다보는지 정리해볼게요.

개념 / 원리

운영체제 책에서는 보통 이렇게 설명합니다.

  • 프로세스(Process): 실행 중인 프로그램. 독립된 메모리 공간(텍스트, 데이터, 힙, 스택)을 가진다.
  • 스레드(Thread): 프로세스 내부의 실행 흐름 단위. 같은 프로세스의 스레드들은 메모리를 공유한다.

근데 리눅스는 조금 특이합니다. 커널 입장에서 보면 프로세스와 스레드를 거의 같은 자료구조(task_struct)로 다뤄요. 단지 메모리 공간을 공유하느냐 안 하느냐가 다를 뿐입니다. 그래서 리눅스에선 스레드를 LWP(Light Weight Process) 라고도 부릅니다.

식별자 정리:

용어 의미
PID Process ID. 프로세스 대표 ID.
TID Thread ID. 각 스레드의 ID(=LWP).
PPID Parent Process ID. 부모 프로세스 PID.
TGID Thread Group ID. 같은 프로세스의 스레드들이 공유. PID와 같음.

핵심은 TGID == PID 라는 점입니다. 멀티스레드 프로세스에서 메인 스레드의 TID는 PID(TGID)와 같고, 추가 스레드들은 같은 TGID를 가진 서로 다른 TID를 갖습니다.

실전 예제

1. 프로세스 트리 보기

ps -ef --forest
pstree -p

-p는 PID도 같이 보여줘서 부모-자식 관계 파악에 좋습니다.

2. 특정 프로세스의 스레드 보기

ps -L -p 1234

출력 예:

  PID   LWP TTY      TIME CMD
 1234  1234 ?    00:00:01 java
 1234  1235 ?    00:00:00 java
 1234  1236 ?    00:00:02 java

LWP 컬럼이 TID입니다. PID는 1234로 같은데 LWP가 1234, 1235, 1236으로 다르죠.

3. /proc로 직접 보기

ls /proc/1234/task/
# 1234  1235  1236

/proc/<PID>/task/ 아래에 스레드 디렉토리가 TID별로 있습니다.

cat /proc/1234/status | grep -E "^(Pid|Tgid|PPid)"

출력:

Tgid:   1234
Pid:    1234
PPid:   1

추가 스레드 자신을 보면 Pid는 TID, Tgid가 프로세스 PID입니다.

cat /proc/1234/task/1235/status | grep -E "^(Pid|Tgid)"
# Tgid:   1234
# Pid:    1235

4. top에서 스레드 단위 보기

기본 top은 프로세스 단위입니다. 실행 중에 H를 누르면 스레드 단위로 전환됩니다.

top -H -p 1234

-H로 시작부터 스레드 모드.

5. CPU 많이 쓰는 스레드 찾기 (Java 단골 절차)

# 1. CPU 잡아먹는 PID 찾기
top
# 2. 그 PID의 스레드 중 범인 찾기
top -H -p <PID>
# 3. TID를 16진수로 변환
printf "%x\n" <TID>
# 4. jstack으로 매칭
jstack <PID> | grep -A 10 nid=0x<hex>

6. 부모-자식 관계 추적

ps -o ppid= -p 1234
pgrep -P 1234

pgrep -P로 자식 프로세스들을 한 번에 뽑을 수 있습니다.

자주 하는 실수

1. PID와 TID 혼동

kill -9 <TID>로 스레드 하나만 죽이려는 시도. 리눅스에서 시그널은 보통 프로세스(TGID) 단위로 처리되고, 특정 스레드만 죽이는 건 tgkill 시스템 콜이 필요합니다. 일반적인 kill <PID>는 프로세스 전체를 종료시킨다고 보면 됩니다.

2. ps만 보고 스레드 수 판단

ps -ef | grep java

이러면 메인 스레드 하나로만 보입니다. ps -eLf 또는 ps -L -p <PID>로 봐야 모든 스레드가 나옵니다.

3. PPID가 1인 이유

부모 프로세스가 자식보다 먼저 죽으면 자식의 PPID는 1(init/systemd)로 바뀝니다. 이게 바로 고아 프로세스가 init에 입양되는 과정이에요. PPID=1이라고 무조건 데몬은 아닙니다.

4. 좀비 프로세스(Z 상태)에 대한 오해

좀비는 메모리를 잡아먹는 게 아니라 PID 슬롯만 차지합니다. 부모가 wait()로 종료 코드를 회수하면 사라져요. ps에서 <defunct>로 표시됩니다.

마무리

정리하면 세 줄입니다.

  • 리눅스에서 스레드는 메모리를 공유하는 LWP일 뿐, 커널 입장에선 프로세스와 거의 같다.
  • TGID(=PID)는 프로세스를, TID(=LWP)는 그 안의 스레드를 식별. /proc/<PID>/task/에 다 있다.
  • 스레드 단위로 보려면 ps -L, top -H. 부모는 PPID, 자식은 pgrep -P로 추적.
반응형