상세 컨텐츠

본문 제목

프로세스-2 (프로세스 생성과 종료)

운영체제

by AyaanDev 2022. 12. 28. 16:29

본문

반응형

이전 포스팅에서 부모 프로세스가 자식 프로세스를 만들어 낼 수 있다고 언급하였다.

이번 포스팅에서는 부모 프로세스가 자식프로세스를 만들어내는 과정과 프로세스의 종료를 설명하겠다.

 

이전 포스팅: https://ayaan-dev.tistory.com/2

 

프로세스 생성 기법

프로세스는 본인의 메모리 영역을 복제하여 자식 프로세스를 만들어낸다. 이는 fork()시스템 콜을 통해 이뤄진다.

다만 fork()시스템 콜만으로는 본인과 똑같은 모습의 자식프로세스만 만들어 낼 수 있다. 이 또한 가치있는 일이나 우리는 컴퓨터를 켜서 chrome을 실행하고 카카오톡을 실행하는등 서로 다른 프로그램을 실행할 필요가 있다. 이를 위해서는 exec()시스템 콜이 필요하다. exec()시스템 콜은 fork()를 통해 생성한 메모리공간에 우리가 원하는 데이터로 덮어쓰는 시스템 콜이다. 아래에서 좀 더 자세하게 알아보겠다.

 

fork() 시스템 콜

fork()는 자기 자신 프로세스의 복사본을 만드는 시스템콜이다. 자식 프로세스는 부모 프로세스의 복사본이기 때문에 부모 프로세스의 자원들이 자식 프로세스에 상속된다. 여기서 말하는 자원이란 메모리의 내용, 열린 파일 목록등을 말한다. 복사된 자식 프로세스라 할지라도 pid값이나 저장된 메모리 위치는 부모프로세스와 다르다.

 

부모 프로세스와 자식프로세스 이 두 프로세스는 fork() 후의 명령어에서부터 실행을 계속하며, 이 때 한 가지 다른 점은 fork()의 return value가 서로 다르다는 것이다. 부모 프로세스의 경우 자식 프로세스의 식별자가 반환되는 반면 자식 프로세스의 경우 0이 반환된다.  pid값은 0보다 큰 정수이므로 fork()로 반환된 값이 0이면 자식프로세스 fork()로 반환된 값이 0 이 아니면 부모프로세스인 것으로 생각할 수 있다.

exec() 시스템 콜

exec()시스템 콜은 할당받은 메모리 공간을 새로운 데이터로 덮어쓰는 시스템콜이다. 예를 들어 bash셀에서 ls명령어를 실행했다고 가정하자. bash셀은 본인과 똑같은 매모리 공간을 fork를 통해 만들어 내고 자식 프로세스에서 exec시스템 콜 호출을 통해 ls명령어를 실행하기위해 필요한 데이터들을 메모리 공간에 적재한다.

 

wait() 시스템 콜

부모 프로세스는 자식과 병행하게 실행을 계속할 수도 있지만 자식프로세스가 실행을 종료할 때 까지 기다려야 할 수도 있다. 이 때 사용하는 시스템 콜이 wait()이다.

 

fork() 예시

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

int main(int argc,char *argv){
        int pid;

    pid=fork();

    if(pid<0){ // 오류가 발생했음.
        fprintf(stderr,"Fork Failed");
        return 1;
    }else if(pid==0){ // 자식 프로세스
        execlp("/bin/ls","ls",NULL);
    }else{
        wait(NULL);
        printf("Child complete\n");
    }
}

execlp 는 exec 계열의 함수이다. exec 계열 함수에는 여러가지가 있으므로 검색해서 확인해보길 권한다.

fork()의 반환값을 pid에 저장하고 if문을통해 자식 프로세스인지 부모프로세스인지를 판단하여 코드를 분할하였다.

부모프로세스의 경우 wait 시스템콜을 통해 자식프로세스가 종료되길 기다리고있으므로 ls명령어가 먼저 실행된 이후에 부모프로세스의 실행이 이어진다. 따라서 터미널의 출력 결과는 아래와 같이 나타난다.

프로세스의 종료

프로세스가 마지막 문장의 실행을 끝내고 exit시스템 호출을 사용하여 운영체제에게 자신의 삭제를 요청하면 종료된다. 이 때 프로세스는 자신의 부모 프로세스에게 상태값을 반환할 수 있다. 이는 wait함수의 매개변수에 나타난다.

pid_t pid;

int status

pid=wait(&status)

위 fork()예시 코드에서는 wait함수에 매개변수로 NULL을 보냈지만 위와같이 정수형 변수를 넘기면 status에 종료 상태값이 저장된다. 또한 wait의 반환값으로는 자식 프로세스의 pid값이 반환된다.

 

프로세스가 종료되면 사용하던자원은 운영체제에 반환된다. 그러나 프로세스의 종료 상태가 저장되는 프로세스 테이블의 해당 항목은 부모 프로세스가 wait()을 호출 할 때 까지 남아있게 된다.

종료되었지만 부모 프로세스가 아직 wait()을 호출하지 않은 프로세스를 좀비 프로세스라 한다.

부모 프로세스가 wait을 호출하는 대신 종료된다면 이러한 상황에 처한 자식프로세스를 고아(orphan)상태라 한다.

Linux와 Unix는 고아 프로세스의 새로운 부모 프로세스로 systemd(init)으로 지정함으로써 이 문제를 해결한다. systemd프로세스는 주기적으로 wait()을 호출하여 고아 프로세스의 종료 상태를 수집하고 프로세스 식별자와 프로세스 테이블 항목을 반환한다.

반응형

'운영체제' 카테고리의 다른 글

다중 스레드 모델(Multithreading Models)  (0) 2023.01.05
실시간 CPU 스케줄링  (0) 2023.01.04
CPU 스케줄링(CPU Scheduling)  (0) 2022.12.28
Thread -1(Thread vs Process)  (0) 2022.12.28
프로세스 -1 (프로세스란)  (1) 2022.12.28

관련글 더보기

댓글 영역