fork후에 signal을 이용한 자식프로세스 처리문제

feivue의 이미지

부모의 어떤 데이타를 처리하기 위해 자식프로세스를 생성하여 처리하고 결과만 다시 재출력하기 위한 소스입니다.

시그널을 통해서 아부지는 자식이 종료신호를 보낼때까지 무한 루프를 돌면서 3초에 한번씩 "Waiting Child Op..." 를 뿌려주고자 하는 코드인데요
제 의도와는 달리 저놈의 문구는 한번도 실행되지도 않고 실행시간동안 멍하니 기다리게 해놓고 이내 끝나버리고 마네요 ~

#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <signal.h>

void sighandler(int signo);

int main(void) {

	pid_t	pid;
	int status,i,j,k,some_array[1000],total=0,delay;

	/*append for signal operation*/
	struct sigaction act;
	act.sa_handler = sighandler;
	act.sa_flags = 0;
	sigemptyset( &act.sa_mask );
	sigaction( SIGCHLD , &act , 0 );

	/* some 1~1000 number data*/
	for(i=0;i<1000;i++) {
  some_array[i] = i+1;
	}

	if ((pid = vfork()) < 0) perror("vfork error");

	else if (pid > 0) { /*parent*/
  printf("Parent Start\n");
  sighandler(pid); /*waiting by signalhandler*/
  printf("Total number : %d\n",total);
  printf("Parent End\n");

	} else { /* child part*/
  printf("Child Start\n");
  for(j=0;j<1000;j++) { /* some 'complicated' operation*/
  	for(k=0;k<=j;k++) {
    total += some_array[k];
    for(delay=0;delay<4000;delay++); /*append delay*/
  	}
  }
  printf("Child End\n");
  exit(13); /*exit with SIGCHLD*/
	}
	exit(0);
}

/*parent's signal handler*/
void sighandler(int signo) {
	printf("Sig Start\n");
	while (waitpid( -1 , 0 , WNOHANG ) > 0 ) { // while child is dead
  sleep(3);
  printf("Waiting child Operation...\n");
	}
	printf("Sig End\n");
}

그래서 원인을 찾아보려고 군데군데 printf를 넣어서 실행순서를 확인해 봤거든요.
그런데 분명히 fork() 후에 아부지 프로세스와 자식프로세스가 동시에 일을 처리하면서 아부지는 아부지대로 기다리면서 메시지를 뿌리고 자식은 자식대로 일을 처리해야 되는거 아닌가요? 근데 실행순서를 보면

Child Op Start
Child Op End
Parent Start
Sig Start
Stg End
Total number : 167167000
Parent End

이상하게도 동시가 아니라 자식 프로세스가 모든 연산을 마치고 난 직후에야 아부지 프로세스가 처리되는군요...

그러니까 당연히 시그널처리를 하는 while은 들어가보지도 못하고 종료되는게 아닐까요

왜 그럴까요, 설마 fork후에는 child processor 를 먼저 처리하고 parent processor 가 처리되는 건 아닐텐데...

아~ 삽질의 끝을 볼 수 있도록 좀 도와주세요~

File attachments: 
첨부파일 크기
파일 tellwait3.c1.19 KB
progcom의 이미지

위 소스를 보니, 시그널 핸들러의 개념을 잡지 못하신듯 싶습니다.

시그널 핸들러를 등록 하면, 그 핸들러는, 해당하는 시그널이 잡힌 순간에 작동하게 됩니다.
즉, 시그널 핸들러를 등록해놓고 다른 일을 하고 있다가, 갑작스레 시그널이 들어오면 등록해둔 함수가 작동하게 되는 것이지요.
(3초 출력을 시그널 핸들러에 놓게 되면 자식 프로세스가 종료했을 때만 실행되겠지요)

SIGCHLD가 발생했을 때, (즉 자식 프로세스가 종료할 때) 자동적으로 시그널 핸들러가 작동합니다. 그때까지 부모 프로세스에서는 계속적으로 반복 실행을 해주면 되겠지요. (3초마다 출력 같은건 당연히 부모 프로세스에서 처리해야합니다)

한번 등록해두면 해당 시그널이 발생할때까지 전혀 작동하지 않는게 시그널 핸들러입니다. 그냥 내버려두고 잊고 있으면! 시그널 발생시에 작동하게됩니다. 부모 프로세스에서 시그널 발생을 기다릴 필요는 없지요.

설명이 잘 안되네요. 더 쉽게 설명하실수 있는 분이 답글 달아주셨으면 좋겠습니다 :)

덧붙임 : vfork()로는 정상적으로 작동하지 않을 듯 싶습니다. ;;

서지훈의 이미지

[APUE pp. 193~194 참고]
여기에 보면 vfork()는 child가 먼저 도는것을 보장을 해주고...
child가 ecec or exit 를 호출하기 전까진 parent는 개입을 하지 않는걸로 되어 있네요...
그러니깐 님이 돌린신 결과가 나오는게 맞는 겁니다.
원래의 결과를 원하시는 거라면...
fork()을 이용을 하시고...
그러나 fork()을 사용을 하실 경우엔 parent와 child는 완전한 다른 곳에서 돌기 때문에...
total 값은 0으로 찍히게 됩니다.

<어떠한 역경에도 굴하지 않는 '하양 지훈'>

#include <com.h> <C2H5OH.h> <woman.h>
do { if (com) hacking(); if (money) drinking(); if (women) loving(); } while (1);

danielkim의 이미지

아래 코드를 참고하시고 처리하시면 될듯하네요
컴파일을 안해 보고 코드를 수정해 드리니 syntax 에러는 직접
처리하시기 바랍니다. 아래 코드 참고하세요

#include <sys/types.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <sys/wait.h> 
#include <signal.h> 

int is_child_killed = 0;
void sighandler(int signo); 

int main(void) { 

   pid_t   pid; 
   int status,i,j,k,some_array[1000],total=0,delay; 

     /* ******************************************** */
    //  initializing the global variable to check the  child is killed or not
     /* ******************************************** */
 
    is_child_killed = 0;

   /*append for signal operation*/ 
   struct sigaction act; 
   act.sa_handler = sighandler; 
   act.sa_flags = 0; 
   sigemptyset( &act.sa_mask ); 
   sigaction( SIGCHLD , &act , 0 ); 

   /* some 1~1000 number data*/ 
   for(i=0;i<1000;i++) { 
  some_array[i] = i+1; 
   } 

   if ((pid = vfork()) < 0) perror("vfork error"); 

   else if (pid > 0) { /*parent*/ 
  printf("Parent Start\n"); 
  //   sighandler(pid); /*waiting by signalhandler*/ 
  while(is_child_killed != 1 ) sleep(1);

  printf("Total number : %d\n",total); 
  printf("Parent End\n"); 

   } else { /* child part*/ 
  printf("Child Start\n"); 
  for(j=0;j<1000;j++) { /* some 'complicated' operation*/ 
     for(k=0;k<=j;k++) { 
    total += some_array[k]; 
    for(delay=0;delay<4000;delay++); /*append delay*/ 
     } 
  } 
  printf("Child End\n"); 
  exit(13); /*exit with SIGCHLD*/ 
   } 
   exit(0); 
} 

/*parent's signal handler*/ 
void sighandler(int signo) { 
int childstatus;
   printf("Sig Start\n"); 
  // while (waitpid( -1 , 0 , WNOHANG ) > 0 ) { // while child is dead 

   while (waitpid( -1 ,&childstatus,  0 ) > 0 ) { // while child is dead 
    is_child_killed  = 1;
   //   sleep(3); 
  //  printf("Waiting child Operation...\n"); 
   } 
   printf("Sig End\n"); 
} 

If you running this code , Parent process will be waiting until child process finishing his useless long task ,

프로세스 제어에 관련된 내용을 개발할때 마다 매번 책을 참고하시고 해서
유의 해서 개발하세요
도움 되길 바랍니다.

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.