Computer >> 컴퓨터 >  >> 프로그래밍 >> C 프로그래밍

단일 C 프로그램으로 좀비 프로세스와 고아 프로세스 동시에 구현하기

이번 글에서는 C/C++ 단일 프로그램 안에서 좀비 프로세스(zombie process)와 고아 프로세스(orphan process)를 동시에 실행하는 방법을 알아보겠습니다. 본격적인 설명에 앞서, 두 프로세스가 각각 어떤 것인지 먼저 살펴보겠습니다.

좀비 프로세스(Zombie Process)

좀비 프로세스는 실행이 이미 종료되었지만 여전히 프로세스 테이블에 항목이 남아 있는 프로세스를 말합니다. 좀비 프로세스는 주로 자식 프로세스에서 발생하는데, 그 이유는 부모 프로세스가 자식의 종료 상태(exit status)를 아직 읽지 않았기 때문입니다. 부모가 wait 시스템 콜을 호출해 자식의 종료 상태를 확인하면, 그제야 좀비 프로세스가 프로세스 테이블에서 제거됩니다. 이 과정을 '좀비 프로세스 수거(reaping)'라고 부릅니다.

고아 프로세스(Orphan Process)

고아 프로세스는 부모 프로세스가 종료되었거나 실행을 마친 이후에도 계속 실행 중인 프로세스를 의미합니다. 고아 프로세스는 의도적으로 만들어질 수도 있고, 의도치 않게 발생할 수도 있습니다.

의도적으로 고아가 된 프로세스는 별도의 사용자 개입 없이 백그라운드에서 실행됩니다. 이는 주로 무한히 실행되는 서비스를 시작하거나, 사용자의 주의 없이 오래 걸리는 작업을 끝까지 처리해야 할 때 활용됩니다.

반면, 의도치 않은 고아 프로세스는 부모 프로세스가 비정상 종료되거나 강제로 종료될 때 생성됩니다. 이런 비의도적인 고아 프로세스는 프로세스 그룹(process group) 메커니즘을 활용하면 방지할 수 있습니다.

이제 다음 코드를 통해 좀비 프로세스와 고아 프로세스를 동시에 실행해 보겠습니다. 여기에는 부모 프로세스가 하나 있고, 이 부모는 자식을 가지며, 그 자식은 또 다른 자식(손자 프로세스)을 가집니다. 실행 흐름이 자식 프로세스로 진입하면 5초간 실행을 멈춰 부모 프로세스가 먼저 종료될 시간을 줍니다. 그 결과 자식 프로세스는 고아 프로세스가 됩니다. 이후 손자 프로세스가 좀비 프로세스로 전환되는데, 손자 프로세스는 자신의 부모(메인 프로세스의 자식)가 1초씩 잠들어 대기하는 동안 실행을 마칩니다. 부모가 종료 상태를 회수하지 않았기 때문에 손자 프로세스의 항목은 프로세스 테이블에 그대로 남게 됩니다.

예제 코드

#include <stdio.h>
#include <unistd.h>
int main() {
    int x = fork(); //create child process
    if (x > 0) //if x is non zero, then it is parent process
        printf("Inside Parent---- PID is : %d\n", getpid());
    else if (x == 0) { //for chile process x will be 0
        sleep(5); //wait for some times
        x = fork();
        if (x > 0) {
            printf("Inside Child---- PID :%d and PID of parent : %d\n", getpid(), getppid());
            while(1)
                 sleep(1);
            printf("Inside Child---- PID of parent : %d\n", getppid());
        }else if (x == 0)
            printf("Inside grandchild process---- PID of parent : %d\n", getppid());
    }
    return 0;
}

실행 결과

soumyadeep@soumyadeep-VirtualBox:~$ ./a.out
Inside Parent---- PID is : 3821
soumyadeep@soumyadeep-VirtualBox:~$ Inside Child---- PID :3822 and PID of parent : 686
Inside grandchild process---- PID of parent : 3822
soumyadeep@soumyadeep-VirtualBox:~$

실행 결과를 살펴보면, 부모 프로세스(PID 3821)가 먼저 종료된 뒤 자식 프로세스(3822)가 출력한 부모 PID가 686으로 바뀐 것을 확인할 수 있습니다. 이는 원래 부모가 종료되면서 자식이 init(또는 systemd) 프로세스의 관리 하에 들어갔음을 의미하며, 자식 프로세스가 고아가 되었음을 보여줍니다. 한편 손자 프로세스는 즉시 실행을 마쳤지만 부모가 wait()를 호출하지 않았기 때문에 좀비 상태로 프로세스 테이블에 남게 됩니다. 이처럼 하나의 프로그램만으로 두 가지 특수한 프로세스 상태를 모두 재현할 수 있습니다.