Step 68. 프로세스의 실체 — fork 실험
Level 1 — 프로그래밍과 컴퓨터 내부 | 난이도 ★★★☆☆ | 예상 소요 시간 3시간
전제: Step 56~67을 마쳤다. C로 간단한 프로그램을 작성하고 gcc로 컴파일할 수 있고, 시스템 콜이 무엇인지 안다.
- 준비물: 리눅스 터미널(WSL 또는 우분투) 하나와 gcc. 오늘은 코드 분량이 적고 실험이 많습니다.
- 주의: 오늘 실습은 안전합니다. 다만 실행할 때마다 결과의 숫자(PID)와 줄 순서가 조금씩 다르게 나오는데, 그것이 버그가 아니라 오늘 배울 내용의 핵심입니다.
지금까지 우리는 프로그램을 "디스크에 저장된 파일"과 "실행 중인 무언가"로 구분해 왔습니다. 실행 중인 그 무언가의 정식 이름이 프로세스(process)입니다. 그런데 이 프로세스는 도대체 어디서 올까요? 정답은 조금 기묘합니다. 컴퓨터를 켰을 때 프로세스 1호가 뜨고, 그 뒤의 모든 프로세스는 이미 있던 프로세스가 자기 자신을 복사해서 만듭니다. 그 복사 명령이 오늘의 주인공 fork()입니다. 여러분이 터미널에 ls를 치는 그 순간에도 쉘이 fork를 합니다 — 오늘은 이 보이지 않던 복제를 눈으로 확인합니다.
1. 학습 목표
이 챕터를 끝내면 다음을 할 수 있습니다:
- 프로세스와 PID, PPID를 설명하고 ps와 pstree로 관찰한다
- fork()의 규칙 세 가지(복제, 메모리 사본, 리턴값 구분)를 말한다
- fork를 n번 호출하면 프로세스가 2의 n제곱 개가 되는 이유를 실험으로 확인한다
- 쉘이 fork와 exec으로 명령을 실행하는 절차를 설명한다
- 프로세스 격리가 왜 보안의 초석인지 설명한다
2. 배경 지식 — 오늘의 도구와 개념
오늘의 도구 한눈에 보기
| 구분 | 내용 |
|---|---|
| 언어·환경 | C 언어 + 리눅스 터미널 (WSL 우분투 24.04에서 실측) |
| 오늘의 명령어 | ps aux(프로세스 목록), pstree -p(프로세스 가계도), sleep N &(백그라운드 실행), jobs(내가 띄운 작업), kill PID(프로세스에 신호 보내기) |
| 오늘의 C 함수 | fork(), getpid()(내 PID), getppid()(부모 PID) |
| 필요한 개념 | 프로세스, PID/PPID, 복제와 메모리 사본, COW(Copy-On-Write), fork + exec |
| 오늘의 산출물 | 프로세스 관찰 일지 — ps/pstree 관찰과 fork 실험 기록 |
2-1. 프로세스와 PID
모든 프로세스에는 PID(Process ID, 프로세스 번호)라는 고유 번호가 붙습니다. 병원 접수 번호표처럼, 운영체제는 이 번호로 각 프로세스를 구분하고 관리합니다. 그리고 각 프로세스는 자신을 만든 부모의 번호인 PPID(Parent PID, 부모 프로세스 번호)도 기억합니다. 이 두 번호만으로 전체 프로세스의 가계도를 그릴 수 있고, 그 가계도를 보여 주는 도구가 pstree입니다.
2-2. fork의 규칙 딱 세 가지
fork()는 C 언어에서 새 프로세스를 만드는 함수로, 규칙은 의외로 단순합니다.
- 호출하면 프로세스가 둘이 된다. 부모(원본)와 자식(복사본)이 fork 호출 직후 지점부터 각자 실행을 계속합니다.
- 메모리가 통째로 복사된다. 자식은 부모의 변수, 배열, 힙까지 그대로 베낀 사본을 받습니다. 사본이라서, 이후 자식이 자기 변수를 바꿔도 부모의 변수는 그대로입니다.
- 리턴값으로 누가 누구인지 구분한다. 이것이 가장 기묘한 부분입니다. 함수 하나를 호출했는데 리턴이 두 번 일어납니다. 부모에게는 자식의 PID(0보다 큰 수)가, 자식에게는 0이 리턴됩니다. 코드에서는 이 리턴값으로 "나는 부모인가 자식인가"를 판별해 서로 다른 일을 시킵니다.
2-3. 왜 복사부터 할까
"새 프로그램을 띄우려면 처음부터 만들면 되지, 왜 굳이 복사를 할까?"라는 의문이 자연스럽습니다. 이유는 효율과 관습입니다. 복사는 놀랍게도 빠릅니다 — 리눅스는 메모리를 즉시 베끼지 않고, 누군가 내용을 바꾸는 순간에만 그 부분을 베끼는 COW(Copy-On-Write, 쓰는 순간 복사) 기술을 씁니다. 게다가 복사본은 부모의 열린 파일, 현재 디렉터리, 환경 변수까지 그대로 물려받기 때문에, 쉘이 명령을 실행할 때마다 작업 환경을 새로 세팅할 필요가 없습니다. 복사 후에 exec 계열 함수로 원하는 프로그램으로 갈아끼우는 것이 리눅스의 표준 절차입니다.
3. 따라 하기
3-1. 프로세스 구경하기 — ps와 pstree
먼저 지금 이 순간 돌고 있는 프로세스들을 봅시다.
입력
ps aux | head -n 6
출력 (2026-09-09 실측):
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 21776 13120 ? Ss 13:32 0:00 /sbin/init
root 2 0.0 0.0 3180 2200 hvc0 Sl+ 13:32 0:00 /init
root 6 0.0 0.0 3224 2152 hvc0 Sl+ 13:32 0:00 plan9 --control-socket 7 ...
root 49 0.0 0.1 34044 12748 ? S<s 13:32 0:00 /usr/lib/systemd/systemd-journald
root 98 0.0 0.0 25012 6316 ? Ss 13:32 0:00 /usr/lib/systemd/systemd-udevd
읽는 법: 두 번째 열이 PID입니다. 1번 프로세스(/sbin/init)는 시스템이 켜질 때 가장 먼저 뜨는 최초의 프로세스입니다. 나머지는 전부 이 1번의 직간접적인 자손입니다.
왜: "지금 몇 개의 프로세스가 돌고 있는가"를 감으로 잡는 것이 첫걸음입니다. 이 목록 전체가 fork로 시작됐다는 사실을 곧 확인합니다.
이어서 가계도를 봅니다.
입력
pstree -p | head -n 8
출력 (2026-09-09 실측):
systemd(1)-+-Relay(683)(678)---python3(686)
|-agetty(201)
|-containerd(190)-+-{containerd}(224)
| |-{containerd}(225)
| `- ...
...
읽는 법: 가지(─, ┬)와 들여쓰기가 부모-자식 관계이고, 괄호 안 숫자가 PID입니다. 꼭대기의 systemd(1)가 모든 프로세스의 조상입니다. 여러분이 방금 실행한 pstree 자신도 이 그림 안에서 쉘(bash)의 자식으로 등장합니다.
왜: 프로세스가 평면적 목록이 아니라 나무 구조라는 것, 그리고 쉘이 명령의 부모가 된다는 것을 시각적으로 확인하는 단계입니다.
3-2. 예측해 보기 — fork를 한 번 호출하면
본격 실험 전에 예측부터 합니다. 아래 프로그램이 출력하는 줄 수는 몇 줄일까요? 변수 x의 값은 각각 얼마일까요? 종이에 적어 두세요.
#include <stdio.h>
#include <unistd.h>
int main(void) {
int x = 100;
pid_t pid = fork();
if (pid == 0) {
x = 999;
printf("자식: x=%d, 내 PID=%d, 부모 PID=%d\n", x, getpid(), getppid());
} else {
printf("부모: x=%d, 내 PID=%d, 자식 PID=%d\n", x, getpid(), pid);
}
return 0;
}
pid_t는 PID를 담는 정수형 타입 이름이고, getpid()는 "나 자신의 PID", getppid()는 "내 부모의 PID"를 알려 주는 함수입니다. if (pid == 0)이 바로 "나는 자식인가?"를 묻는 갈림길입니다.
3-3. 직접 확인 — 복제의 순간
위 코드를 forktest.c로 저장하고 컴파일·실행합니다. 세 번 연속으로 실행해 보세요.
입력
gcc -o forktest forktest.c
./forktest; ./forktest; ./forktest
출력 (2026-09-09 실측):
부모: x=100, 내 PID=1143, 자식 PID=1144
자식: x=999, 내 PID=1144, 부모 PID=1143
부모: x=100, 내 PID=1146, 자식 PID=1147
자식: x=999, 내 PID=1147, 부모 PID=1138
부모: x=100, 내 PID=1149, 자식 PID=1150
자식: x=999, 내 PID=1150, 부모 PID=1149
읽는 법: printf가 한 번밖에 없는데 실행마다 출력이 두 줄입니다. fork 지점에서 실행 흐름이 둘로 갈라져, 부모는 else 칸을, 자식은 if 칸을 지나간 것입니다. 부모의 x는 100, 자식의 x는 999로 서로 다릅니다 — 자식이 x를 바꿨지만 부모의 x는 영향을 받지 않았습니다. 메모리가 복사됐기 때문입니다. PID 숫자는 실행할 때마다 바뀝니다.
그런데 두 번째 실행을 자세히 보세요. 자식이 찍은 부모 PID가 1138로, 진짜 부모(1146)와 다릅니다. 부모가 찍은 자식 번호(1147)와 자식 자신의 번호(1147)는 일치하는데 말이죠. 부모가 먼저 종료해 버리면 고아가 된 자식은 다른 프로세스에게 입양되고, 그 뒤에 getppid()를 부르면 새 양부모의 번호가 나옵니다. 실행할 때마다 결과가 미묘하게 다른 것이 정상이며, 그 이유까지 설명할 수 있어야 진짜 이해입니다.
왜: 이 출력이 fork의 규칙 세 가지 전부를 증명합니다. 출력 순서가 위아래로 뒤바뀌어 나올 때도 있는데, 둘 중 누가 먼저 CPU를 배정받는지가 매번 다르기 때문이며 역시 정상입니다.
3-4. 예측해 보기 — fork를 세 번 연속 호출하면
난이도를 올립니다. 아래 코드를 실행하면 프로세스가 모두 몇 개가 될까요?
#include <stdio.h>
#include <unistd.h>
int main(void) {
fork();
fork();
fork();
printf("PID=%d\n", getpid());
return 0;
}
힌트: 첫 번째 fork에서 1개가 2개로, 두 번째 fork는 그 2개 각각이 복제되므로 4개로, 세 번째는 그 4개 각각이 복제됩니다. fork3.c로 저장하고 직접 확인해 보세요.
입력
gcc -o fork3 fork3.c
./fork3 | wc -l
./fork3 | sort -u | wc -l
출력 (2026-09-09 실측):
8
8
읽는 법: wc -l은 줄 수를 셉니다. 출력이 정확히 8줄 — 2의 3제곱입니다. 두 번째 명령은 sort -u(겹치는 줄 제거)까지 거쳐도 8줄이라는 것, 즉 8줄의 PID가 전부 서로 다른 번호라는 것까지 확인합니다. 8개의 프로세스가 각각 존재했다는 증거입니다.
왜: fork가 "지수적으로" 불어난다는 감각은 보안에서 중요합니다. 무한 루프에서 fork를 호출하는 포크 폭탄(fork bomb)이라는 고전 공격이 있는데, 프로세스 수를 폭발적으로 늘려 시스템을 마비시키는 단순하고 무서운 코드입니다. 오늘 8개를 본 여러분은 그 폭탄이 왜 무서운지 원리로 이해하게 된 셈입니다. (포크 폭탄은 자기 랩에서도 절대 실행하지 마세요. 원리만 이해하면 충분합니다.)
3-5. 쉘에서 직접 프로세스 만들고 관찰하기
마지막으로 코드 없이 쉘에서 프로세스를 만들고 관찰합니다.
입력
sleep 30 &
jobs
ps aux | grep "sleep 30" | grep -v grep
출력 (2026-09-09 실측):
[1] 1188
[1]+ Running sleep 30 &
root 1188 0.0 0.0 3132 1900 pts/2 S+ 13:37 0:00 sleep 30
읽는 법: sleep 30은 30초간 아무것도 안 하고 자는 프로그램이고, 끝의 &는 "백그라운드(뒷전)에서 실행해 달라"는 뜻입니다. 첫 줄의 [1] 1188에서 1188이 이 프로세스의 PID이고, jobs(내가 띄운 백그라운드 작업 목록)와 ps 양쪽에서 같은 번호로 보입니다. 이 명령을 치는 순간에도 쉘이 fork로 자식을 만들고, 그 자식이 sleep으로 변신(exec)한 것입니다.
이 프로세스를 끄는 명령은 kill 1188입니다. kill은 이름과 달리 "프로세스에 신호를 보내는" 명령이고, 기본 신호가 종료 요청이라 결과적으로 프로세스를 끕니다. (이 책의 실측 랩 규칙상 저는 kill을 실행하지 않았으므로 출력 예시로만 보여 드립니다: [1]+ Terminated sleep 30.) 여러분의 터미널에서는 30초 뒤에 저절로 끝나므로 기다려도 되고, 직접 kill로 끝내 봐도 됩니다.
왜: PID가 단순한 번호가 아니라 운영체제가 프로세스를 지휘하는 손잡이라는 것을 몸으로 익히는 단계입니다. 나중에 침해사고 분석에서 "이상한 프로세스를 찾아 PID로 끄는" 일을 바로 이 손놀림으로 하게 됩니다.
3-6. strace로 fork의 진짜 모습 보기 (출력 예시)
Step 67의 strace를 기억하시나요? fork도 결국 커널에 대한 부탁, 즉 시스템 콜입니다. strace가 설치된 환경이라면 직접 확인해 보세요. (이 책의 실측 랩에는 strace가 없으므로 아래는 출력 예시입니다.)
입력 (예시)
strace -f -e trace=clone ./forktest 2>&1 | head -n 4
출력 예시 (일반적인 우분투 환경에서의 모습):
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|...) = 1144
부모: x=100, 내 PID=1143, 자식 PID=1144
자식: x=999, 내 PID=1144, 부모 PID=1143
+++ exited with 0 +++
읽는 법: 리눅스에서 fork는 내부적으로 clone이라는 시스템 콜로 구현되어 있습니다. -f는 "자식까지 따라가며 추적해 달라", -e trace=clone은 "clone 부탁만 골라 보여 줘"라는 뜻입니다. clone의 리턴값이 부모가 받은 자식 PID와 정확히 일치하는 것을 확인하세요.
왜: "라이브러리 함수 → 시스템 콜 → 커널" 삼단 흐름이 fork에도 그대로 적용됩니다. 프로세스 생성조차 커널의 문지방을 통과하는 부탁이며, 그래서 감시 도구는 새 프로세스의 탄생을 전부 볼 수 있습니다.
4. 미션과 연습문제
미션 — 프로세스 관찰 일지
ps aux에서 PID 1번 프로세스를 찾고, 그 이름을 적습니다pstree -p에서 자신의 쉘(bash)을 찾아, 그 부모가 누구인지 위로 따라가 봅니다- forktest.c를 세 번 연속 실행하며, 매번 출력 순서와 PID가 어떻게 달라지는지 기록합니다. 자식이 찍은 부모 PID가 진짜 부모와 다른 사례가 나오면 그 이유를 추론해 적습니다
sleep 60 &을 두 번 실행해 프로세스 두 개를 띄우고,ps aux | grep sleep으로 둘의 PID를 확인한 뒤, 하나는 kill로 끄고 하나는 1분 뒤 저절로 끝나는 것을jobs로 확인합니다- 마무리로 "fork의 리턴값이 왜 두 개인가?"를 자기 말로 세 문장 안에 설명하는 글을 씁니다
연습문제
문제 1. fork() 한 줄로 출력이 두 줄 나오는 이유를 "대본과 배우"의 관점으로 설명해 보세요.
문제 2. fork를 세 번 연속 호출하면 프로세스가 8개가 되는 과정을 단계별로 설명해 보세요.
문제 3. 자식이 x를 999로 바꿨는데 부모의 x가 100 그대로인 이유와, 이 성질이 보안에서 왜 중요한지 설명해 보세요.
문제 4. 쉘에 ls를 입력했을 때 일어나는 일을 fork와 exec, wait 세 단어를 써서 설명해 보세요.
5. 모범 답안과 완료 기준
미션 모범 답안
관찰 일지의 뼈대 예시입니다 (2026-09-09 실측 근거 — 여러분의 PID와 트리 모습은 다를 수 있습니다):
1. PID 1 = /sbin/init (pstree에서는 systemd(1)로 표시) — 모든 프로세스의 조상
2. 내 bash의 부모는 ... 위로 올라가면 결국 1번에 닿는다
3. forktest 3회: PID는 매번 증가하는 새 번호(1143/1144 → 1146/1147 → 1149/1150).
2회차에서 자식의 부모 PID가 1138로 다르게 찍힘 → 부모가 먼저 종료되어
자식이 다른 프로세스에게 입양된 것(고아 프로세스의 재입양)
4. sleep 둘의 PID 확인 후 kill 하나 → jobs에서 Terminated 확인,
남은 하나는 60초 뒤 Done으로 바뀜
5. fork는 호출 후 세상에 프로세스가 두 개가 된다. 리턴이 두 번인 게 아니라
두 프로세스가 각자 한 번씩 리턴받는다. 그래서 같은 호출인데 부모는 자식 PID를,
자식은 0을 받는다.
검증하는 법: ① fork3의 | wc -l이 8이었는가. ② sort -u까지 쳐도 8인지(서로 다른 PID 8개) 확인했는가. ③ 관찰 일지에 "순서는 매번 다를 수 있다"가 기록됐는가. 셋이 ‘예’이면 완성입니다.
연습문제 해답
문제 1 해답. fork 아래 줄부터는 두 명의 배우(부모와 자식 프로세스)가 같은 대본(코드)을 읽습니다. 대본은 하나, 배우는 둘입니다. printf는 대본에 한 줄뿐이지만 두 배우가 각자 읽으므로 출력은 두 줄입니다. 리턴값(부모: 자식 PID, 자식: 0)이 각자의 대사가 갈리는 지점입니다.
문제 2 해답. 첫 번째 fork에서 1개가 2개로 갈라집니다. 두 번째 fork 줄에 도달한 것은 그 2개이고 각자 복제하므로 4개가 됩니다. 세 번째 fork 줄에 도달한 4개가 각자 또 복제해 8개가 됩니다. 2×2×2 = 2³ = 8. printf는 한 줄이지만 8개의 프로세스가 각자 실행하므로 출력도 8줄입니다 (2026-09-09 실측으로 확인).
문제 3 해답. 자식은 부모 메모리의 사본을 받기 때문입니다. 원본과 사본은 복제 순간 이후 완전히 별개입니다. 이 성질이 중요한 이유: 거꾸로 말하면 어떤 프로세스도 다른 프로세스의 메모리를 멋대로 들여다볼 수 없다는 뜻이기 때문입니다. 이 격리가 없다면 브라우저 프로세스에서 은행 앱 프로세스의 비밀번호를 그냥 읽을 수 있을 것입니다. 프로세스 격리는 운영체제 보안의 출발점입니다.
문제 4 해답. ① 쉘이 fork로 자기 복사본(자식)을 만듭니다. ② 자식이 exec 계열 함수로 자기 몸을 요청받은 프로그램(ls)으로 갈아끼웁니다. ③ 부모인 쉘은 자식이 끝나길 wait로 기다렸다가 프롬프트를 다시 보여 줍니다. &를 붙이면 ③의 기다림을 건너뛰는 것뿐입니다. 명령 한 줄이 매번 복제와 변신의 의식이었던 것입니다.
완료 기준 체크리스트
- [ ] 프로세스와 PID, PPID를 설명할 수 있다
- [ ] fork()의 규칙 세 가지(복제, 메모리 사본, 리턴값 구분)를 말할 수 있다
- [ ] fork를 세 번 호출하면 프로세스가 8개인 이유를 설명할 수 있다
- [ ] 자식이 찍은 부모 PID가 다를 수 있는 이유(재입양)를 설명할 수 있다
- [ ] 쉘이 fork와 exec, wait으로 명령을 실행하는 절차를 설명할 수 있다
- [ ] ps와 pstree로 프로세스 목록과 가계도를 읽을 수 있다
- [ ] 미션: 프로세스 관찰 일지를 완성했다
6. 흔한 실수와 해결
벽 1. 출력 순서가 매번 달라요
증상: forktest를 실행할 때마다 부모가 먼저 나왔다가 자식이 먼저 나왔다가 합니다.
원인: 운영체제의 스케줄러(어떤 프로세스에게 CPU를 줄지 정하는 관리자)가 그때그때 사정에 따라 순서를 정하기 때문입니다.
해결: 고장이 아니라 정상입니다. "순서는 보장되지 않는다" 자체가 fork의 성질입니다. 순서가 필요하면 부모가 자식을 기다리는 wait() 함수를 씁니다.
벽 2. fork()의 리턴값이 왜 두 번 나오는지 이해가 안 돼요
증상: "함수 하나가 어떻게 값을 두 번 리턴해?"라는 생각에 막힙니다.
원인: 리턴이 두 번인 게 아니라, 호출 이후 세상에 프로세스가 두 개 존재하게 되고 각자 한 번씩 리턴을 받는 것입니다.
해결: "fork 아래 줄부터는 두 명의 배우가 같은 대본을 읽는다"라고 상상하세요. 대본은 하나, 배우는 둘. 리턴값이 각자의 대사가 다른 이유입니다.
벽 3. 자식이 바꾼 값이 부모에게 반영되지 않아요
증상: 자식에서 변수를 바꿨는데 부모에서 그대로입니다 (3-3 실측의 x=100).
원인: 자식은 부모 메모리의 사본을 받습니다. 원본과 사본은 복제 순간 이후 완전히 별개입니다.
해결: 이것은 오류가 아니라 프로세스 격리라는 보안의 초석입니다. 프로세스끼리 값을 주고받으려면 파이프 같은 별도 통신 수단(IPC)이 필요합니다.
벽 4. 자식이 찍은 부모 PID가 진짜 부모와 달라요
증상 (2026-09-09 실측): 자식: x=999, 내 PID=1147, 부모 PID=1138 — 부모는 분명 1146인데 1138이 찍힙니다.
원인: 부모가 자식보다 먼저 종료하면, 고아가 된 자식은 운영체제가 정한 다른 프로세스에게 입양됩니다. 그 뒤 getppid()는 새 양부모의 번호를 돌려줍니다.
해결: 버그가 아니라 리눅스의 정상 동작입니다. 부모가 자식보다 오래 살아 있게 하려면 부모 쪽에 wait(NULL);을 넣어 자식의 종료를 기다리게 하세요.
벽 5. 컴파일은 됐는데 실행하면 출력이 이상해요
증상: printf가 있는데 출력이 없거나 겹쳐 보입니다.
원인: printf의 출력은 버퍼(임시 보관함)에 모았다가 한꺼번에 냅니다. fork 직후 버퍼가 통째로 복사되면서 내용이 두 번 나오거나 타이밍이 어긋날 수 있습니다.
해결: printf 문자열 끝에 \n(줄바꿈)이 있는지 확인하고, 그래도 이상하면 fflush(stdout);를 fork 전에 넣어 버퍼를 비운 뒤 복제하세요.
7. 정리
오늘의 개념
| 개념 | 한 줄 설명 |
|---|---|
| 프로세스 | 실행 중인 프로그램의 실체 — 고유 번호 PID를 달고 있다 |
| PID / PPID | 프로세스 번호 / 부모 프로세스 번호 — 가계도를 그리는 두 축 |
| fork() | 프로세스 복제 함수 — 부모는 자식 PID, 자식은 0을 리턴 |
| COW (Copy-On-Write) | 복사를 미루고 쓰는 순간에만 베끼는 기술 — fork가 빠른 이유 |
| fork + exec | 쉘의 명령 실행 절차: 복제 후 자식이 프로그램으로 변신 |
| 포크 폭탄 | fork 무한 반복으로 시스템을 마비시키는 공격 — 원리만 이해, 실행 금지 |
오늘의 명령어·함수
| 명령어·함수 | 하는 일 |
|---|---|
ps aux |
지금 돌고 있는 프로세스 목록 (두 번째 열이 PID) |
pstree -p |
프로세스 가계도 (괄호 안이 PID) |
명령 & / jobs |
백그라운드 실행 / 내가 띄운 작업 목록 |
kill PID |
프로세스에 신호 보내기 (기본: 종료 요청) |
fork() |
프로세스 복제 (리턴: 부모는 자식 PID, 자식은 0) |
getpid() / getppid() |
내 PID / 부모 PID 알아내기 |
명령어보다 중요한 감각
"실행"이라는 단어의 실체가 선명해졌습니다. 파일이 프로세스가 되는 문지방, 그리고 프로세스가 프로세스를 낳는 방식까지 — 운영체제의 일상이 여러분의 손끝에서 재현됐습니다. 기억할 숫자는 하나, fork n번 = 프로세스 2ⁿ개. 기억할 문장도 하나, "자식이 바꿔도 부모는 모른다." 이 격리가 없다면 어떤 프로그램도 남의 메모리를 볼 수 있을 테고, 운영체제는 이 격리를 목숨 걸고 지키며, 공격자는 이 격리를 넘으려고 온갖 기술을 개발합니다.
보안과의 연결: 여러분이 실험에서 띄우고 관찰한 프로세스들은 전부 여러분의 랩에서 여러분이 만든 것들이었습니다. 이 원칙 — 내가 만든 것을 내 랩에서만 — 은 앞으로의 모든 실험에서도 그대로입니다. 모든 공격 실습은 내 랩·합법 플랫폼에서만. 실서비스 무단 공격은 범죄입니다.
전부 체크되면 Step 68 완료입니다. 사이드바의 체크박스를 눌러 진도를 저장하세요.