리눅스 fork

IT 위키
현재 프로세스를 복제해 자식 프로세스를 만드는 시스템 호출

유닉스·리눅스에서 새 프로세스는 오직 기존 프로세스를 복제해서만 만들어진다. 부팅 직후의 init(또는 systemd) 하나에서 시작해 fork 를 거듭한 결과가 지금의 프로세스 트리다.

  • 호출한 프로세스(부모)의 메모리 이미지, 열린 파일 디스크립터, 환경 변수를 그대로 복사해 자식 프로세스를 만든다.
  • 자식은 새로운 PID 를 받고, 자식의 PPID 는 부모의 PID 가 된다.
  • 반환값이 둘이다. 이것이 fork 의 특징이다.
    • 부모에게는 자식의 PID 를 돌려준다.
    • 자식에게는 0 을 돌려준다.
    • 실패하면 −1 을 돌려준다.
  • 실제 구현은 메모리를 통째로 복사하지 않고 쓰기 시 복사(Copy-on-Write)를 써서, 어느 쪽이든 메모리를 고칠 때 비로소 복사한다.
pid_t pid = fork();

if (pid < 0)        { /* 실패 */ }
else if (pid == 0)  { /* 자식 프로세스 */ }
else                { /* 부모 프로세스, pid 는 자식의 PID */ }

exec 계열과의 관계

[편집 | 원본 편집]
  • fork 는 프로세스를 복제만 한다. 자식은 여전히 부모와 같은 프로그램을 실행한다.
  • exec(execve, execl, execvp …) 는 새 프로세스를 만들지 않고 현재 프로세스의 메모리 이미지를 다른 프로그램으로 덮어쓴다. PID 는 그대로다.
  • 그래서 셸이 명령을 실행하는 과정은 fork 로 자신을 복제한 뒤 자식에서 exec 로 대상 프로그램을 덮어쓰는 형태다.
셸(bash, PID 1000)
   └ fork() → 자식(PID 1001, 여전히 bash)
                └ exec("/bin/ls") → 같은 PID 1001 이 ls 가 된다

관련 개념

[편집 | 원본 편집]
  • wait() / waitpid() : 부모가 자식의 종료를 기다리고 종료 상태를 회수한다.
  • 좀비 프로세스 : 자식은 끝났는데 부모가 종료 상태를 회수하지 않아 프로세스 표에만 남은 상태. psZ 또는 defunct 로 보인다.
  • 고아 프로세스 : 부모가 먼저 죽은 자식. init(PID 1)이 입양해 뒤처리를 맡는다.
  • 포크 폭탄 : fork 를 무한히 반복해 프로세스 표를 고갈시키는 공격. /etc/security/limits.confnproc 으로 사용자별 프로세스 수를 제한해 막는다.
  • vfork : 메모리를 복사하지 않고 곧바로 exec 하는 용도의 변형. clone 은 리눅스가 스레드까지 포괄해 제공하는 더 일반적인 시스템 호출이다.

같이 보기

[편집 | 원본 편집]