fork
와 자식 프로세스는 유닉스 계열 운영 체제에서 매우 중요한 개념으로, 프로세스 생성과 관련이 있다. fork
시스템 호출은 새로운 프로세스를 생성하는 데 사용되며, 이 새로운 프로세스를 자식 프로세스라고 한다.
fork
시스템 호출은 호출하는 프로세스를 복제하여 동일한 프로그램 코드, 데이터, 파일 디스크립터 등을 갖는 새로운 프로세스를 생성한다. 이때 부모 프로세스와 자식 프로세스는 동일한 메모리 공간을 공유하는 것이 아니라, 별도의 메모리 공간을 갖게 된다. 그러나 초기 상태에서는 부모 프로세스의 메모리 내용이 자식 프로세스에 그대로 복사된다. fork
는 호출 시 두 번 반환되는데, 부모 프로세스에서는 자식 프로세스의 PID를 반환하고, 자식 프로세스에서는 0을 반환한다. 이를 통해 부모와 자식 프로세스를 구분할 수 있다.
fork
의 주요 역할은 다음과 같다.
첫째, 멀티태스킹 지원이다. fork
를 사용하면 여러 프로세스가 동시에 실행될 수 있으며, 이를 통해 멀티태스킹을 구현할 수 있다. 예를 들어, 서버 애플리케이션은 fork
를 사용하여 클라이언트의 요청을 처리하기 위해 새로운 프로세스를 생성할 수 있다.
둘째, 부모-자식 프로세스 구조이다. fork
를 통해 생성된 자식 프로세스는 부모 프로세스와 동일한 환경을 가지고 시작하지만, 독립적으로 실행된다. 자식 프로세스는 독립적으로 실행되기 때문에, 부모 프로세스와 자식 프로세스가 병렬로 작업을 수행할 수 있다.
셋째, 프로세스 분기이다. fork
를 사용하여 프로그램의 실행 흐름을 분기할 수 있다. 자식 프로세스는 부모 프로세스의 복제본이지만, fork
호출 이후에는 자식 프로세스와 부모 프로세스가 서로 다른 작업을 수행하도록 프로그래밍할 수 있다.
fork
를 통해 생성된 자식 프로세스는 보통 exec
계열의 시스템 호출과 함께 사용된다. exec
시스템 호출은 자식 프로세스의 메모리 공간을 새로운 프로그램으로 덮어쓰는 역할을 한다. 이를 통해 자식 프로세스는 부모 프로세스와는 다른 프로그램을 실행할 수 있다. 예를 들어, 부모 프로세스는 사용자 명령을 읽고, fork
를 통해 자식 프로세스를 생성한 후, 자식 프로세스에서 exec
를 호출하여 사용자가 요청한 프로그램을 실행할 수 있다.
다음은 fork
와 자식 프로세스를 사용하는 간단한 예제이다.
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
pid_t pid = fork();
if (pid < 0) {
// fork 실패
perror("fork failed");
return 1;
} else if (pid == 0) {
// 자식 프로세스
printf("자식 프로세스: PID = %d\n", getpid());
execlp("/bin/ls", "ls", NULL); // 예: ls 명령어 실행
} else {
// 부모 프로세스
printf("부모 프로세스: PID = %d, 자식 프로세스 PID = %d\n", getpid(), pid);
wait(NULL); // 자식 프로세스가 종료될 때까지 대기
}
return 0;
}
이 예제에서 fork
는 새로운 자식 프로세스를 생성하며, 자식 프로세스는 ls
명령어를 실행하도록 execlp
를 호출한다. 부모 프로세스는 자식 프로세스가 종료될 때까지 기다린다.
결론적으로, fork
와 자식 프로세스는 유닉스 계열 운영 체제에서 프로세스를 생성하고 멀티태스킹을 지원하는 중요한 메커니즘이다. fork
를 통해 생성된 자식 프로세스는 부모 프로세스와 독립적으로 실행되며, exec
와 결합하여 다양한 프로그램을 실행할 수 있다. 이를 통해 시스템은 효율적으로 자원을 관리하고, 병렬로 작업을 처리할 수 있다.