Researcher to Developer

프로세스 생성 시스템 콜 - fork(), exec() - 2 본문

카테고리 없음

프로세스 생성 시스템 콜 - fork(), exec() - 2

Probe29 2021. 1. 1. 16:52

#fork(), exec()

 

리눅스 프로세스 실행 과정에 필요한 두 가지 시스템 콜이다.

 

fork() - 부모 프로세스로 부터 새로운 프로세스 공간을 만들고 부모 프로세스 데이터 복사 

exec() - 새로운 프로세스를 위한 바이너리를 새로운 프로세스 공간에 덮어씌움

 

풀어서 설명하면 다음과 같다.

프로세스 내에서 fork()를 호출하면 새로운 프로세스에 대한 공간을 만들고

fork()를 호출한 프로세스(부모) 데이터를 복사하여

pid가 0이면 자식 프로세스, pid가 0보다 크면 부모 프로세스로 공간이 나뉘게 된다.

그리고 새로운 프로세스를 위한 코드 이미지를 새로운 프로세스 공간에 덮어씌운다.

 

그런데 fork() 함수 호출을 하면 자식 프로세스가 종료하기 전에 부모 프로세스가 끝나는 오류가 생길 수 있다.

자식 프로세스 정보가 계속 메모리에 떠 있는 좀비 혹은 고아 프로세스 현상이 나타나기 때문에

이를 방지하기 위한 해결책이 필요한데, 그것이 wait () 시스템 콜이다.

 

 

 

#wait() 시스템 콜

 

wait() 함수를 사용하면, fork 함수 호출 시 자식 프로세스가 종료할 때 까지 부모 프로세스가 기다린다.

자식 프로세스와 부모 프로세스의 실행 순서의 동기화를 위해,

부모 프로세스가 자식 프로세스보다 먼저 죽는 경우를 막기 위해 사용한다.

(고아 프로세스, 좀비 프로세스 : 자식 프로세스 정보가 메모리에 계속 떠 있음)

 

부모, 자식 프로세스와 시스템 콜 관계도

 

기본개념

쉘에 wait() 함수를 넣으면 자식 프로세스가 끝날 때까지 기다린다.
자식 프로세스가 종료되면 Defalut로 SIGCHLD 시그널이 부모 프로세스에 보내진다.

자식 프로세스가 종료되면 자식 프로세스가 어떻게 종료되었는지 나타내는 여러 정보들이 
메모리에 공간을 차지하고 있고, 그것을 부모 프로세스가 확인을 한 다음에 자식 프로세스가 죽게된다. 

 

a. 부모 프로세스에 wait () 함수가 있을 경우

wait ()함수가 SIGCHLD 시그널을 받아서 wait() 함수 밑 줄 함수를 읽어나가게 된다.


b. 부모 프로세스에 wait () 함수가 없을 경우
wait ()함수가 없으면 기다리지 않고 부모 프로세스가 먼저 끝나버리게 되는데, 
그럴 경우 자식 프로세스는 정보를 계속 메모리에 넣어서 리소스를 불필요하게 사용하게 된다. (고아 프로세스)

 

 

 

#fork(), execl(), wait() 시스템 콜 함수

int main() {
     int pid;
     int child_pid;
     int status;
     pid = fork ();                    
     switch (pid) {
          case -1:
               perror("fork is failed\n");
               break;
          case 0:
               execl("/bin/ls", "ls", "-al", NULL);
               perror("execl is failed\n");
               break;
          defalut                                                   // 0 보다 크면 부모 프로세스
               child_pid = wait(NULL);                         // 자식 프로세스가 끝날 때까지 기다린다.
               printf("ls is complete\n");      
               printf("Parent PID (%d), Child PID (%d)\n", getpid(), child_pid);
               exit(0);
}

                               // main 함수에서 fork 후 pid가 -1이 나오면 fork 실패, 0 이면 자식 프로세스

 

위 함수는 다음과 같이 진행된다.


fork 를 통해 새로운 프로세스 공간이 생성되고(based on parent process)
그 공간에 자식 프로세스에서 실행 시킨 새로운 실행 파일이 ls 바이너리로 덮어씌워진다.
chile_pid = wait(NULL);  자식 프로세스가 끝날 때까지 기다린다.
그리고 ls 바이너리로 인해 파일리스트 출력을 한 뒤 

끝나면 부모 프로세스에 시그널(SIGCHLD) 을 받을 때까지 기다렸다가 

시그널을 받으면 wait 이하 코드를 실행하게된다.

execl() 만 사용하면 부모 프로세스가 사라지기 때문에
부모 프로세스를 유지하기 위해, fork ()로 새로운 프로세스 공간 복사 후 execl() 사용한다.
wait() 함수를 사용해서 부모 프로세스가 자식 프로세스가 끝날 때까지 기다릴 수 있다.