본문 바로가기

Operating System

[Ch 3-2] Process creation, termination

3.3 Operations on Processes

3.3.1 Process Creation

실행 중인 프로세스는 새로운 프로세스를 만들 수 있는데, 이 때 프로세스를 만드는 입장을 parent process, 이에 의해 새롭게 생긴 것을 child process라고 한다. Child process는 또 새로운 child process를 만들 수 있을 것이므로, 이런 식으로 프로세스들이 트리 구조를 이루게 된다. 각 프로세스는 고유한 번호인 process identifier (이하 pid)를 가지며, kernel은 이 번호를 인덱스로 사용하여 각 프로세스의 속성에 접근하게 된다.

 

아래 그림은 Linux OS에서 프로세스들이 트리 구조를 이루고 있는 것을 나타낸다.

출처: 교재 Figure 3.7

시스템이 부팅되자마자 systemd라는 프로세스가 생기는데, 이것은 이후에 생기는 모든 user process의 parent process가 된다.

 

하나의 프로세스가 새로운 프로세스를 만들어졌을 때, parent process는 children process와 동시에 실행될 수도 있고, children process의 일부 또는 전체가 종료될 때까지 기다릴 수 있다. 또한 address space 측면에서는, child process가 parent process의 복사본을 받을 수 있고, 아니면 새로운 프로그램이 load될 수 있다.

 

이 두 가지 측면의 차이를 아래 예제 코드를 통해 이해할 수 있다.

 

Example code

#include <stdio.h>
#include <sys/types.h>	// fork()
#include <unistd.h>		// fork()
#include <sys/wait.h>	// wait()

int main(){
	pid_t pid;
	
	pid = fork();
	
	// child process
	if (pid == 0) {
		printf("----- child process -----\n");
		execlp("/bin/ls", "/bin/ls", NULL);
	}	
	
	// parent process
	else {
		wait(NULL);
		printf("----- parent process -----\n");
	}
    
	return 0;
}

fork()라는 system call을 실행하면 새로운 프로세스를 만들게 된다. 이 때, fork() 함수의 return 값이 parent process에서는 child process의 pid 값이고, child process에서는 0이다.

 

이 때 기본적으로 child process는 parent process의 address space의 복사본을 가지게 된다. 따라서 같은 코드를 동시에 실행하는 식이 되는데, 일반적으로는 child process에서 exec() system call을 통해 다른 프로그램을 load하여 실행하게 된다. 여기서는 디렉토리에 있는 것들을 출력하는 ls 를 실행하도록 하였다.

다음으로, child process가 종료될 때까지 parent process가 기다릴 수 있는데, 이것은 wait() system call에 의해 가능하다. 이 예제 코드에서는 parent process가 wait() call을 해서 child process가 종료되기를 기다리도록 하였다. 이 프로그램에 대한 실행 결과는 위와 같다. 먼저, child process가 실행되서 ls 를 실행한 뒤 종료되고, parent process가 실행을 이어나간 뒤 종료된 것이다. 이를 graph 형태로 표현하면 아래와 같다.

출처: 교재 Figure 3.9

 

3.3.2 Process Termination

프로세스가 실행을 종료할 때는 exit() system call이 일어남으로써 OS에게 프로세스를 삭제할 것을 요청한다. OS는 해당 프로세스에게 할당된 자원들을 모두 deallocate 시킴으로써 종료시킨다.

 

하나의 프로세스가 다른 프로세스를 적절한 system call을 통해 종료시킬 수도 있는데, 일반적으로 이것은 parent process에 의해서만 가능하도록 되어 있다. 만약 child process가 할당된 자원을 초과하여 사용했거나, child에 할당된 task가 더 이상 필요 없게 되거나, parent process가 종료될 때가 그러하다.

 

그런데 child process가 종료되더라도 parent process에서 wait()을 호출하기 전까지는 process table 상에는 남아있게 된다. 이것은 zombie process라고 부르는데, 왜냐하면 아직 process의 exit status를 확인해야 하기 때문이다.

 

Reference

A. Silberschatz, Operating System Concepts 10th ed, WILEY (2019) Ch 3