좀비 프로세스에 관한 질문입니다

yanggak의 이미지

while(1)
{
    ......
    ......
                if( (pid = fork()) == 0){
                        printf("\n\nexec\n\n);
                        exit();
                }

                if(ground != BACKGROUND) {
                        wait(&status);
                }
                else {
                        ground = 0;
                        printf("Child process PID : %d\n", pid);
                 }
}

다음과 같이 실행되었을때
부모프로세스보다 자식 프로세스의 실행이 먼저 끝나게 되면
자식프로세스는 어떻게 되나요??
background의 개념이 이런거 아닌가요?
답변부탁드립니다.
alwaysN00b의 이미지

부모프로세스보다 자식 프로세스의 실행이 먼저 끝나게 되면

자식 프로세서가 끝나고 부모 프로세서가 wait 하기전까진
좀비 프로세서가 됩니다..( <defunct> )

프로세서 실행중 ps 해보면 자식프로세서의 ppid 는 부모 프로세서의 pid
인데 부모 프로세서가 먼저죽으면 자식프로세세의 ppid는 1 이 됩니다.

언제나 시작

arimae의 이미지

parent, child 관계에서 child 보다 parent 가 먼저 종료 될 경우.. child의 parent는 init가 됩니다.
따라서 나중에 child가 종료되면 init 가 알아서 child 에 할당된 자원을 해제해 줍니다.

이런 것을 이용해서 concurrent server 를 짤때 좀비가 생기지 않도록 double fork를 사용하기도 합니다.

자세한 것은 Advanced Programming in the Unix Environment 202 page를 보시면 소스가 나와있습니다.

Dream, Passion and Challenge..

arthor77의 이미지

좀비프로세스란 왜톨이 부모가 버린 프로세스란 말이다.
부모가 버렸으니, 상식적으로 할아버지와 할머니의 손에서 양육되어야 할것이다.
부모 프로세스가 자식을 버리니, 이는 가화만사성이 깨지고 할아버지 init 프로세스가 그자식을 살피니 이는 비극이요, 있을수 없는 일이로다.

jinyeong의 이미지

zombie process 란 process가 종료후 parent process가 child process의

상태를 wait(or waitpid) 등으로 종료 반환 값을 읽어가고 관련 리소스를

해제해주기를 대기하는 상태를 말합니다.

parent가 이를 호출하지 않고, child 보다 먼저 죽었을 경우 init 이 해당 process의

parent가 되어 child의 zombie 상태를 해제하게 됩니다.

I thought what I'd do was,
I'd pretend I was one of those deaf-mutes.. or should I?

yanggak의 이미지

구체적으로 init이 좀비가 된 프로세스를 언제 어떻게 죽이는지에 대한 답변은 안나온것 같군요...
예를 들어서 위의 소스에서 계속해서 루프를 돌면서 fork를 한다면 계속 좀비프로세스가 생기지 않을까요?
제가 실력이 없는 터라 프로그램을 돌리다 위와 같은 상황을 초래한것같습니다..
linux server로 접속하려하니 이런 메시지가 뜨더군요.

fork:resource temporarily unavailble

뭣 땜에 이러는 건가요? vitual memory하고 관계있는것 같다고 어떤 사람이 얘기해 주던데...궁금합니다.

If you can dream it,
you can do it

jinyeong의 이미지

Quote:

fork:resource temporarily unavailble

virtual memory 때문이라기 보다는 시스템에서 허용된 process의 갯수를 초과했기 때문일 것 같습니다.

Quote:

예를 들어서 위의 소스에서 계속해서 루프를 돌면서 fork를 한다면 계속 좀비프로세스가 생기지 않을까요?
제가 실력이 없는 터라 프로그램을 돌리다 위와 같은 상황을 초래한것같습니다..

위에서 ground 변수가 정확히 언제 setting 되는 건가요?
상태가 BACKGROUND라면 계속 fork 하게 되는 거 아닌가요?
실제로 명시적인 wait는 없이 말이죠.

BACKGROUND의 경우에 sig_handler를 사용해서, waitpid로 처리하시면 zombie 문제는 사라질 것 같습니다.

I thought what I'd do was,
I'd pretend I was one of those deaf-mutes.. or should I?

alwaysN00b의 이미지

init 프로세서가 부모잃은 child 프로세서를 정상적으로 처리한다면

<defunct> 는 왜 생기는 건가요? (궁금 :shock: )

언제나 시작

맹고이의 이미지

alwaysN00b wrote:
init 프로세서가 부모잃은 child 프로세서를 정상적으로 처리한다면

<defunct> 는 왜 생기는 건가요? (궁금 :shock: )

<defunct>는 부모가 살아있고 자식이 죽었을 때 생기는 거 아닌가요?

부모까지 죽어야 init 프로세스가 처리하죠...

물론 그전에 부모가 거두어 줘야 되겠지만.

yundream의 이미지

맹고이 wrote:
alwaysN00b wrote:
init 프로세서가 부모잃은 child 프로세서를 정상적으로 처리한다면

<defunct> 는 왜 생기는 건가요? (궁금 :shock: )

<defunct>는 부모가 살아있고 자식이 죽었을 때 생기는 거 아닌가요?

부모까지 죽어야 init 프로세서가 처리하죠...

물론 그전에 부모가 거두어 줘야 되겠지만.

프로세스는 일단 종료하면 좀비상태가 됩니다.
정확히 말하자면 exit한 프로세스는 부모 프로세스가 wait()하기 전까지는
좀비 상태입니다.

프로세스가 exit()하면 모든 자원을 되돌려주지만, 커널 프로세스 구조체에는
여전히 프로세스 ID와 종료상태 등의 값을 가지고 있습니다.
왜 가지고 있냐 하면 부모 프로세스가 종료된 자식 프로세스의 PID, 종료상태,
리턴값등을 확인할 필요가 있기 때문입니다.

만약 프로세스가 종료하는 즉시 자원과 함께 커널 프로세스(스케쥴)구조체를 날려
버린다면 부모 프로세스는 자식 프로세스의 상태를 알 방도가 없을 겁니다.

wait()를 하면 비로서 해당 커널 프로세스 구조체를 정리하고 좀비상태에서 벗어나게
되고 부모프로세스는 죽은 자식프로세스의 정보를 얻게 됩니다.
물론 SIGCHLD등을 무시하도록 해서 exit호출후 곧바로 프로세스 구조체를
날려버려서 좀비가 발생하지 않도록 하는 방법도 있긴 합니다.

맹고이의 이미지

yundream wrote:
프로세스는 일단 종료하면 좀비상태가 됩니다.
정확히 말하자면 exit한 프로세스는 부모 프로세스가 wait()하기 전까지는
좀비 상태입니다.

프로세스가 exit()하면 모든 자원을 되돌려주지만, 커널 프로세스 구조체에는
여전히 프로세스 ID와 종료상태 등의 값을 가지고 있습니다.
왜 가지고 있냐 하면 부모 프로세스가 종료된 자식 프로세스의 PID, 종료상태,
리턴값등을 확인할 필요가 있기 때문입니다.

만약 프로세스가 종료하는 즉시 자원과 함께 커널 프로세스(스케쥴)구조체를 날려
버린다면 부모 프로세스는 자식 프로세스의 상태를 알 방도가 없을 겁니다.

wait()를 하면 비로서 해당 커널 프로세스 구조체를 정리하고 좀비상태에서 벗어나게
되고 부모프로세스는 죽은 자식프로세스의 정보를 얻게 됩니다.
물론 SIGCHLD등을 무시하도록 해서 exit호출후 곧바로 프로세스 구조체를
날려버려서 좀비가 발생하지 않도록 하는 방법도 있긴 합니다.

허접했지만 제 말이 그 말이었는데...

제 글을 인용하셨길래 남겨봅니다. ;;

ulra의 이미지

안녕하세요.

wait를 써도 부모 프로세서는 정지되지 않게 하는 방법 없나요?

wait를 쓰면 좀비가 없어서 좋긴한데, 부모 프로세서가 정지가 되어서

제가 원하는 기능으로 동작않네요. 방법이 없나요?

OTL 즐!!!! (좌절 금지!!!)

leilei의 이미지

ulra wrote:
안녕하세요.

wait를 써도 부모 프로세서는 정지되지 않게 하는 방법 없나요?

wait를 쓰면 좀비가 없어서 좋긴한데, 부모 프로세서가 정지가 되어서

제가 원하는 기능으로 동작않네요. 방법이 없나요?

signal과 함께 wait/waitpid를 이용합니다...
왠만한 유닉스 시스템 프로그래밍 책을 보시면 당연히 나오는 이야기입니다... :(

vness의 이미지

그럼 signal을 고려해 보시는건 어떻습니까?

SIGCHLD 를 이용해 보심이..

child process가 종료하면 child process는 parent process에게

SIGCHLD를 보내게 되어 있습니다.

하나의 parent process에 child process가 여러놈이면 한꺼번에 SIGCHLD가

여러번 넘어 올 수 있으므로(signal은 queueing을 할 수 없습니다.) 그것을 고려해 주어야 하겠지만..

단순히 parent - child 의 쌍이라면 별 고민없이 사용하시면 될 듯합니다.

ulra의 이미지

답변 감사드립니다.

제가 프로그래밍 초보이고 지금 책이 없습니다.

예제 소스를 받을수 있는 곳이나 또는 직접 예제를 올려주시면 안될까요?

OTL 즐!!!! (좌절 금지!!!)

leilei의 이미지

vness wrote:

하나의 parent process에 child process가 여러놈이면 한꺼번에 SIGCHLD가

여러번 넘어 올 수 있으므로(signal은 queueing을 할 수 없습니다.) 그것을 고려해 주어야 하겠지만..

그렇습니다.. 때문에 거의 모든 문서의 예제에는 while()안에 wait()을 넣고 있습니다.. -_-;

initiative의 이미지

아래 소스는 TCP/IP 소켓 프로그래밍에 예시된 

멀티프로세싱 에코서버입니다.

/*
 * echo_multiserv.c
 * H.jin
 * 2004.5.24
 */

 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
 #include <unistd.h>
 #include <signal.h>
 #include <sys/wait.h>
 #include <sys/socket.h>
 #include <arpa/inet.h>

 #define BUFSIZE 30
 #define TRUE 1
 
 void error_handling(char *message);
 void z_handler(int sig);
 
 int main(int argc, char **argv)
 {
 	int serv_sock;
	int clnt_sock;
	struct sockaddr_in serv_addr;
	struct sockaddr_in clnt_addr;

	struct sigaction act;
	int addr_size,
		str_len,
		state;
	pid_t pid;	
	char message[BUFSIZE];
	
	/* 주소 재사용 */
	int option;
	socklen_t optlen;

	if(argc!=2)
	{
		printf("USage: %s <port>\n", argv[0]);
		exit(1);
	}

	act.sa_handler = z_handler;
	sigemptyset(&act.sa_mask);
	act.sa_flags = 0;

	state = sigaction(SIGCHLD, &act, 0);	/* signal handler 등록 */
	if(state!=0)
	{
		puts("sigaction() error");
		exit(1);
	}

	serv_sock = socket(PF_INET, SOCK_STREAM, 0);
	if(serv_sock == -1)
		error_handling("socket() error");
	optlen = sizeof(option);
	option = TRUE;
	
	/* SO_REUSEADDR option */
	setsockopt(serv_sock, SOL_SOCKET, SO_REUSEADDR, &option,
			sizeof(option));

	memset(&serv_addr, 0, sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	serv_addr.sin_port = htons(atoi(argv[1]));

	if( bind(serv_sock, (struct sockaddr*)&serv_addr,
		sizeof(serv_addr)) == -1)
		error_handling("bind() error");
	
	if( listen(serv_sock, 5) == -1)
		error_handling("listen() error");
	
	while(1)
	{
		addr_size = sizeof(clnt_addr);
		clnt_sock = accept(serv_sock, (struct sockaddr*) &clnt_addr,
			&addr_size);
		if(clnt_sock == -1) continue;

		/* 클라이언트의 연결을 독립적으로 생성 */
		if( (pid = fork())== -1) 	/* if fork fail */
		{
			close(clnt_sock);
			continue;
		}
		else if(pid >0)			/* 부모 프로세스의 경우 */
		{
			puts("연결 생성");
			close(clnt_sock);
			continue;
		}
		else			/* 자식 프로세스 의 경우 */
		{
			close(serv_sock);

			/* 자식 프로세스의 처리 영역: 데이터 수신 및 전송 */
			while( (str_len = read(clnt_sock, message, BUFSIZE)) != 0){
				write(clnt_sock, message, str_len);
				write(1, message, str_len);
			}

			puts("연결 종료! ");
			close(clnt_sock);
			exit(0);
		}
		
	}
	return 0;
 }

 void z_handler(int sig)
 {
	pid_t pid;
	int rtn;

	pid = waitpid(-1, &rtn, WNOHANG);
	printf("소멸된 좀비의 프로세스 ID : %d\n", pid);
	printf("리턴된 데이타 : %d\n\n", WEXITSTATUS(rtn));
 }

 void error_handling(char *message)
 {
 	fputs(message, stderr);
	fputc('\n', stderr);
	exit(1);
 }


참고하세요.
자식 프로세스의 종료처리에 대한 SIGCHLD 를 핸들러에서 처리하고
waitpid() 는 wait() 과 동일하지만 블로킹문제를 해결하는 기능이 있습니다.

With Everlasting Passion about new Tech. and Information!

ulra의 이미지

감사합니다. 좋은 하루 되세요. :)

OTL 즐!!!! (좌절 금지!!!)

monovision의 이미지

Quote:
물론 SIGCHLD등을 무시하도록 해서 exit호출후 곧바로 프로세스 구조체를
날려버려서 좀비가 발생하지 않도록 하는 방법도 있긴 합니다.

이 방법은 어떤 식으로 할 수가 있나요 ?

Quote:
하나의 parent process에 child process가 여러놈이면 한꺼번에 SIGCHLD가

여러번 넘어 올 수 있으므로(signal은 queueing을 할 수 없습니다.) 그것을 고려해 주어야 하겠지만..

지금 제가 처한 상황이 위와 같은 상황입니다.
한번에 엄청나게 fork 를 했다가 비주기적으로 종료가 되기 때문에 시그널이 많이 겹치는 상황이라
정상적으로 처리를 해도 좀비 프로세스가 꽤 남고 있습니다.

monovision의 이미지

일단, while 문으로 좀비가 남지 않을때까지 wait, waitpid 을 반복하여 급한 불은 껐지만...
생각외로 좀비가 늦게 죽네요.
exit 호출 후에 곧바로 프로세스 구조체를 날려버릴 수 있는 방법을 아시는 분이 계시면 알려주시면 감사하겠습니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.