리눅스 시스템에서는 프로세스를 생성하는 시스템 호출 fork, vfork 함수를 제공하고 있습니다. fork와 vfork는 프로세스 자신의 프로그램 이미지를 비롯하여 많은 정보를 복제한 자식 프로세스를 생성합니다.
#include <sys/types.h >
#include <unistd.h>
pid_t fork(void);
pid_t vfork(void);
반환 값: 부모에게는 자식 pid(>0), 자식에게는 0, 실패 시 -1
fork와 vfork 함수를 수행하면 현재까지 수행한 상태의 자신을 복제하여 자식 프로세스를 생성합니다. 이 때 부모 프로세스에게는 자식 프로세스의 pid를 반환하며 자식 프로세스에게는 0을 반환합니다. 만약 실패하면 -1을 반환하고 errno에 적절한 실패 이유를 설정합니다. 따라서 양수를 반환하면 현재 수행하는 프로세스는 부모 프로세스이며 0은 자식 프로세스, -1이며 실패라는 말입니다.
자식 프로세스에게 pid를 0을 주는 이유는 자식 프로세스에서는 필요하면 getppid 시스템 호출로 부모 프로세스의 pid를 알아낼 수 있기 때문입니다. 하지만 부모 프로세스에서는 자식 프로세스의 pid를 알 수 있는 방법은 fork와 vfork에 의해 반환하는 pid를 기억하는 방법을 사용해야 합니다.
다음은 fork 시스템 호출후에 반환 값에 따라 getpid와 getppid를 호출하여 부모 프로세스와 자식 프로세스의 관계를 확인하기 위한 예제 코드입니다.
/********************************************************************** * ex_fork.c * * exmple source – create child process * **********************************************************************/ #include <stdio.h> #include <unistd.h> #include <sys/types.h> int main() { printf("start...\n"); printf("pid: %u ppid:%u \n", getpid(), getppid()); pid_t cpid = fork(); if(cpid == -1) { perror("error fork"); return 1; } if(cpid>0) { printf("<parent> fork return value:%u\n",cpid); printf("<parent> pid:%d ppid:%d\n", getpid(), getppid()); sleep(1); } else { printf("<child> fork return value:%u\n",cpid); printf("<child> pid:%d ppid:%d\n", getpid(), getppid()); } return 0; }
실행 결과를 보면 마치 if(cpid>0) 조건문에서 if 블록과 else 블록 모두 수행하는 것처럼 느낄 수도 있습니다. 하지만 자신의 프로세스 ID와 부모의 프로세스 ID를 살펴보면 if 블록은 원래 수행하고 있는 프로세스와 같다는 것을 알 수 있습니다. 그리고 else 블록의 부모 프로세스 ID는 원래 수행하고 있던 프로세스의 ID입니다. 따라서 fork 시스템 호출 이전에 수행하던 부모 프로세스는 if 블록을 수행하고 fork 시스템 호출에 의해 새로 만들어진 자식 프로세스는 else 블록을 수행하고 있음을 알 수 있습니다.