좀비 프로세스 생성과 소멸
좀비 프로세스는 껍데기만 남아있는 상태이다
좀비 프로세스란?
- zombie process, defunct process라고도 한다
- 실행이 종료되었지만 os의 process table을 점유하고 있는 프로세스
- os가 관리하는 process table의 크기에는 제한이 있기 때문에 좀비 프로세스가 계속 생성되면 더 이상 프로세스 생성이 불가능할 수 있다
- parent가 자신의 exit status를 확인하기를 기다리고 있는 상태이다
- child의 exit status를 확인하는 방법에는 두 가지가 있다
example code
- child process는 defunct process가 되는 예제
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, const char *argv[])
{
pid_t p;
if ((p = fork()) == 0) // child
return 0;
else // parent
while (1) { sleep(10); }
return 0;
}
ps -ef | grep <프로세스 이름>
실행 --> [프로세스 이름] \<defunct> 출력
좀비 프로세스 발생을 막는 방법
wait
류 함수 호출- signal handler 등록
wait
- wait를 호출하면 child process의 main 함수가 반환한 값을 확인할 수 있다
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
int main(int argc, const char *argv[])
{
pid_t p;
int estatus;
if ((p = fork()) == 0) // child
return 99;
else { // parent
wait(&estatus);
printf("child(%d) exit status: %d\n",
p, estatus);
while (1) sleep(10);
}
return 0;
}
signal
- child의 main 함수가 반환하면 parent에게 SIGHLD signal이 전달되는데 이 시그널을 받았을때 waitpid로 종료된 child의 exit status를 읽을 수 있다
sigaction
을 사용하면 signal에 대해signal
함수보다 섬세한 제어가 가능하다. signal보다는 sigaction 사용이 권장된다signal
함수는 핸들러가 실행되는 동안 새로운 시그널이 프로세스에 전달되는 것을 막지 않는다. 하지만sigaction
은 시그널 핸들러가 반환하기 전까지 다른 시그널을 막는다(block)signal
함수는 보통 시그널 핸들러가 한 번 호출되고 나면 해당 시그널에 대한 핸들러를SIG_DFL
로 초기화한다- 근데 내 환경(6.8.0-48-generic #48~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC x86_64)에서는 시그널 핸들러가 유지됐다
signal
함수의 위와 같은 동작은 UNIX 구현체마다 다르다. 표준이 이를 허용하고 있다
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <sys/wait.h>
#define DO_USEFUL_TASKS do { sleep(10); } while(1);
void sigchld_handler(int signo)
{
pid_t p;
int estatus;
int opt = 0;
waitpid(-1, &estatus, opt);
printf("child(%d) exit status: %d\n",
p, estatus);
}
int main(int argc, const char *argv[])
{
pid_t p;
int estatus;
if ((p = fork()) == 0) {// child1
printf("child(%d) exit\n", getpid());
return 1;
}
else { // parent
signal(SIGCHLD, sigchld_handler);
// signal(SIGCHLD, SIG_DFL); // 좀비 생성
// signal(SIGCHLD, SIG_IGN); // 좀비 생성 안됨
}
if ((p = fork()) == 0) {// child2
printf("child(%d) exit\n", getpid());
return 2;
}
DO_USEFUL_TASKS
return 0;
}
references
- [WIKIPEDIA] Zombie process
- [Quora] signal 함수보다 sigaction 함수를 써야하는 이유
- [Stackoverflow] signal vs sigaction