10-3 좀비 프로세스 해결법 [TCP/IP][C][LINUX]
프로세스가 할 일을 다 하고도 사라지지 않고 리소스를 차지하고 있는 모습을 가리켜 좀비 프로세스라고 합니다.
fork() 함수의 호출로 생성된 프로세스를 종료하는 방법은 인자를 전달하면서 exit를 호출하거나, main 함수에서 return문을 실행하면서 값을 반환하는 경우가 있습니다.
exit의 인자 값, return의 반환 값 모두 운영체제로 전달되고, 운영체제는 이 값이 부모 프로세스에게 전달될 때까지 자식 프로세스를 소멸시키지 않는데, 이 상황의 프로세스를 좀비 프로세스라 칭합니다.
따라서 자식 프로세스가 종료되며 나온 반환값이나 인자값이 부모 프로세스에게 전달되어야 좀비 프로세스를 없앨 수 있습니다.
부모 프로세스가 자식 프로세스의 전달 값을 요청하는 방법은 두 가지가 있습니다.
먼저 wait 함수를 호출하는 방법입니다.
#include<sys/wait.h>
pid_t wait(int *statloc);
//success: 자식 프로세스의 ID fail: -1
statloc에는 자식 프로세스가 정상 종료했는지, 자식 프로세스가 어떤 값을 전달했는지가 담깁니다. 각각 받아오기 위해서는 매크로함수를 이용하면 됩니다.
WIFEXITED(statloc) : 정상 종료 했다면 true
WEXITSTATUS(statloc) : 자식 프로세스의 전달 값
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>
int main(int argc, char *argv[]){
int status;
pid_t pid=fork();
if(pid==0){
return 3;
}
else{
printf("Child PID: %d \n",pid);
pid=fork();
if(pid==0){
exit(7);
}
else{
printf("Child PID: %d \n",pid);
wait(&status);
if(WIFEXITED(status))
printf("Child send one: %d\n",WEXITSTATUS(status));
wait(&status);
if(WIFEXITED(status))
printf("Child send one: %d\n",WEXITSTATUS(status));
sleep(10);
}
}
return 0;
}
위 코드는 wait 함수를 이용해서 좀비프로세스를 없애는 예제입니다. sleep(10)을 준 이유는 프로그램을 후면에서 실행하고 ps au 명령어를 통해 좀비프로세스가 없는 것을 확인하기 위함입니다. 만약 wait 함수를 없애고 실행하게 되면 STAT이 Z+인 프로세스를 확인할 수 있습니다.
후면처리 방법은 https://pupuduck.tistory.com/65 게시물을 참고해주시기 바랍니다.
다만 wait 함수를 사용하면 종료된 자식 프로세스가 없을 때 블로킹 상태(함수가 반환을 안하는 상태)에 놓이게 됩니다.
그래서 부모 프로세스가 자식 프로세스의 전달 값을 요청하는 방법의 두 번째이자 블로킹 상태의 해결책은 waitpid 함수의 호출을 고려할 수 있습니다.
#include<sys/wait.h>
pid_t waitpid(pid_t pid, int * statloc, int options);
// success: 자식 프로세스의 ID 또는 0 fail: -1
// pid : 종료를 확인하려는 자식 프로세스의 ID, -1 전달 시 wait함수와 같음
// statloc : wait함수의 statloc와 같음
// options : WHOHANG을 인자로 전달하면 블로킹 상태에 있지 않고 0을 반환함
주석으로 써놨듯, options 인자로 WHOHANG을 전달하면 블로킹 상태에 있지 않습니다. 예시 코드는 다음과 같습니다.
#include<stdio.h>
#include<unistd.h>
#include<sys/wait.h>
int main(int argc, char *argv[]){
int status;
pid_t pid=fork();
if(pid==0){
sleep(15);
return 24;
}
else{
while(!waitpid(-1,&status,WNOHANG)){
sleep(3);
puts("sleep 3sec.");
}
if(WIFEXITED(status)){
printf("Child send %d \n",WEXITSTATUS(status));
}
}
return 0;
}
자식 프로세스는 15초 후 24를 반환하는데, 위와 같이 3초를 5번(15초) 기다리며 블로킹 되지 않고 자식 프로세스의 반환값을 반환하는걸 볼 수 있습니다.