SIGNAL의 동시처리 방법

danielkim의 이미지

안녕하십니까?
Daniel Kim 입니다.

거의 동시점에 발생하는 SIGCHLD 의 처리 방법에 관한 의견을 구합니다.


void  process_childdead(int sig) 
{
        // to do something work that takes a litte long time  
         waitpid(... ... 
}


void main ( ) 
{
             .... 
           signal(SIGCHLD, process_childdead);
            ....
          // 여러개의 child process 를 동시에 fork한다. 
          exec_childs(.... )
}

위의 형태의 코드가 있을때 process_childdead 코드 내에 약간의 시간이
걸리는 코드가 들어가 있다고 가정합니다.
이때 exec_childs 에서 수행한 child1, child2, child3 , ... ... childN 입니다.
이때 child1의 prcess_childdead를 수행하는 도중 child2가 죽는 다면
과연 어떻게 처리해야 할까요?( 저는 현재 약간의 꼼수로 이러 처리한 상태입니다)

현재까지 제가 테스트한 결과를 보면 child2는 [defunc] 로 처리가 되는 군요
이걸 피할 방법을 찾고 있습니다.

많은 의견 기대합니다.

답변 주신분들께 미리 감사 드립니다.

-------------------------------------------

hb_kim의 이미지

많은 유닉스 커널에서 시그널은 큐로 관리되지 않고, 비트 플래그로 기록되기때문에 한 시그널의 여러 인스턴스가 발생해도 시그널 핸들러는 한번밖에 수행되지 않습니다.

게다가 시그널 핸들러 수행도중에 시그널이 또 발생하면 핸들러 수행이 중단됩니다. 이것을 막기 위해선 POSIX sigaction() 을 사용하거나, 시그널 핸들러 시작시에 해당 시그널을 블록해줍니다.

void signal_handler(int sig_num)
{
        signal(sig_num, SIG_IGN);

...
...

        signal(sig_num, signal_handler);
}

여기까지는 교과서에 나오는 것을 베낀것이구요.

여러개의 시그널이 중첩되어 있는 경우의 처리는 루프를 돌면서 가능한 시그널 발생 요인을 모두 확인, 처리해주면 되지 않을까요?

zeroness의 이미지

다음과 같이 하면 되지 않을까요...저것도 꽁수라 하시면 할말은 없지만....ㅡㅡ;;

void  process_childdead(int sig) 
{ 
        // 시그널 재 설정
        signal(SIGCHLD, process_childdead); 

        // to do something work that takes a litte long time  
         waitpid(... ... 
} 


void main ( ) 
{ 
             .... 
           signal(SIGCHLD, process_childdead); 
            .... 
          // 여러개의 child process 를 동시에 fork한다. 
          exec_childs(.... ) 
}

인간에게 있어 열정은 둘도없이 소중한 것이다. 경력이나 학력보다도... - 월리엄 록펠러 1세 -

ㅡ,.ㅡ;;의 이미지

zeroness wrote:
다음과 같이 하면 되지 않을까요...저것도 꽁수라 하시면 할말은 없지만....ㅡㅡ;;

void  process_childdead(int sig) 
{ 
        // 시그널 재 설정
        signal(SIGCHLD, process_childdead); 

        // to do something work that takes a litte long time  
         waitpid(... ... 
} 


void main ( ) 
{ 
             .... 
           signal(SIGCHLD, process_childdead); 
            .... 
          // 여러개의 child process 를 동시에 fork한다. 
          exec_childs(.... ) 
}

꽁수가 아닌듯..


----------------------------------------------------------------------------

dhjung의 이미지

만약 사용하시는 시스템이 solaris이고,
child의 exit status 는 상관이 없으시다면, sigaction의 SA_NOCLDWAIT 를 사용하시면 됩니다..


--------------------------
Donghyun Jung

moonzoo의 이미지

약간 다른 시각이지만.

추가적으로

parent가 종료하기 직전에도 wait() 돌려주는 건 어떨까요?

defucnt로 걸려있는 child들을 모두 수거할 수 있지 않을까요?

danielkim의 이미지

daniel Kim 입니다.
여러분들이 주신 좋은 제안들 감사합니다.

zeroness의 이미지

조인씨에 가보니 좋은 강좌가 있네요~
www.joinc.co.kr 에서 "시그널" 또는 "SIGNAL" 으로 검색해
보세요.. ^^

인간에게 있어 열정은 둘도없이 소중한 것이다. 경력이나 학력보다도... - 월리엄 록펠러 1세 -

vinus의 이미지

동시에 여러개의 시그널이 발생 하는데, 예를 드신것 처럼, SIGCHLD가 거의 동시
적으로 발생 할 경우 에 대한 것이라고 생각 하고 제가 사용 하는 방법을 적어
봅니다.

예를 들어 100개 혹은 200개 이상의 자식 프로세스가 언제 종료 될지 모르는
상황에서 프로세스가 관리 되고 있다고 생각하겠습니다.

기본적으로 시그널 처리 함수 부분.
/* 시스템에 따라 정의 안되어 있는 경우 있슴 */

#ifndef WAIT_ANY
#define WAIT_ANY -1
#endif
void process_childdead(int sig)
{
	int pid=0;
	int w;	
	/*  아래 라인이 없을 경우 문제가 발생하는 
	    시스템 있을 수 있슴.  
 	signal (SIGCHLD, process_childdead);
	*/
	while(1)
	{
		pid=waitpid(WAIT_ANY, &w, WNOHANG);
		if(pid<0)
		{
			return;
		}
		/*  이경우 뭔가 시간이 걸리는 작업실행.
                    예을 들면, 자식 프로세스관리 구조체에
		    대한 갱신등..
		*/
	}
}
대충 처리 함수는 이상과 같이 사용 하면 되지 않을 까 생각 합니다.
더 좋은 방법을 알고 계시다면,... 가르쳐 주시면 감사 하겠습니다.

그리고 저렇게 대규모의 자식 프로세스를 관리 한다는 것은 언제나,
좀비가 발생할 가능성이 있습니다. 그러니 메인 프로세서에서는 정기적으로
raise(3)등의 함수를 이용하여 자기 자신에게 시그널을 보내 주면, 대부분의
경우 해결이 가능 할듯 합니다.

raise(SIGCHLD);
뭐 이런식이면, 아래의 시그널 처리 함수로 들어 가게 될것이고, 좀비화 되어
있는 자식들을 거두어 들일수 있습니다.

>>>행복한 웃음<<<

ulra의 이미지

안녕하세요.

sender_sigchld는 무엇인가요?

sender_sigchld는 정의되어 있지않아서 소스를 이해할수 없습니다.

제가 초보라서 풀 소스를 보여주시면 안될까요?

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

vinus의 이미지

음 죄송합니다.

이 부분은 저의 실수 이군요.--> 버그 입니다.
지금 짜고 있는 프로그램의 SIGCHLD처리 부분을 그냥 가져다 붙이다 발행한
일반적인 카피 페이스트 오류라고 할 수 있습니다.
process_childdead 이 맞습니다.

#ifndef WAIT_ANY 
#define WAIT_ANY -1 
#endif 
void process_childdead(int sig) 
{ 
   int pid=0; 
   int w;    
   /*  아래 라인이 없을 경우 문제가 발생하는 
       시스템 있을 수 있슴.  
    signal (SIGCHLD, process_childdead); 
   */ 
   while(1) 
   { 
      pid=waitpid(WAIT_ANY, &w, WNOHANG); 
      if(pid<0) 
      { 
         return; 
      } 
       
      /*  WEXITSTATUS 등의 메크로를 사용하시면, 자식 프로세스의 
           종료 상태를 알수 있을 겁니다.
          
           이경우 뭔가 시간이 걸리는 작업실행. 
                    예을 들면, 자식 프로세스관리 구조체에 
          대한 갱신등.. 
      */ 
   } 
}

보다 자세한 사항들은 man (man waitpid)을 이용하여 보십시오.

>>>행복한 웃음<<<

vness의 이미지

게다가 시그널 핸들러 수행도중에 시그널이 또 발생하면 핸들러 수행이 중단됩니다.

이게 정확한 내용인가요? 제가 알고 있기론 signal handler 가 수행되는 동안에는

그 signal 이 블럭 된다고 알고 있는데요.

SIGCHLD 가 문제가 되고 child process의 종료 상태에 관심이 없으시다면..

프로그램 시작시..

signal(SIGCHLD, SIG_IGN); 

을 추가해주시면 될 것입니다.

최종호의 이미지

vinus wrote:
음 죄송합니다.

이 부분은 저의 실수 이군요.--> 버그 입니다.
지금 짜고 있는 프로그램의 SIGCHLD처리 부분을 그냥 가져다 붙이다 발행한
일반적인 카피 페이스트 오류라고 할 수 있습니다.
process_childdead 이 맞습니다.

#ifndef WAIT_ANY 
#define WAIT_ANY -1 
#endif 
void process_childdead(int sig) 
{ 
   int pid=0; 
   int w;    
   /*  아래 라인이 없을 경우 문제가 발생하는 
       시스템 있을 수 있슴.  
    signal (SIGCHLD, process_childdead); 
   */ 
   while(1) 
   { 
      pid=waitpid(WAIT_ANY, &w, WNOHANG); 
      if(pid<0) 
      { 
         return; 
      } 
       
      /*  WEXITSTATUS 등의 메크로를 사용하시면, 자식 프로세스의 
           종료 상태를 알수 있을 겁니다.
          
           이경우 뭔가 시간이 걸리는 작업실행. 
                    예을 들면, 자식 프로세스관리 구조체에 
          대한 갱신등.. 
      */ 
   } 
}

보다 자세한 사항들은 man (man waitpid)을 이용하여 보십시오.

waitpid() 의 리턴값이 0보다 작은 경우에만 시그널 핸들러를 빠져나가는 것은
가끔 문제를 일으킬 수 있습니다.

아래 스레드를 보시면 정확히 waitpid()가 0을 리턴했는지는 원제출자가 명시를
해주지 않아서 확실치는 않지만, waitpid가 0을 리턴한 경우로 추측되어서
시그널 핸들러에서 상당한 시간을 잡아먹는 경우를 보실 수 있습니다.

http://bbs.kldp.org/viewtopic.php?t=39299

ulra의 이미지

바쁘신데 죄송합니다. 다른 질문이 생겼는데요.

시그널처리함수에서 시그널을 꼭 재설정 해야하나요?

그리고 제가 실험삼아 시그널 처리함수가 언제 호출되는지 알아봤는데요.

자식 프로세스가 죽지 않았는데도 호출이 됩니다. 이유가 무엇인가요?

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

sunyzero의 이미지

보통 윗분말씀대로 거의 동시에 발생된 SIGCHLD가 merge되어 나올때는 시그널 핸들러를 waitpid로 처리하는게 맞습니다. 다만 조금 첨언을 달면

waitpid() 처리시에 WNOHANG외에 WUNTRACED를 같이 넣어서 멈춰있는 녀석과 처리지연이 없게 해야 합니다. 또한 waitpid()의 반환값도 0이나 -1을 다 검사해야 합니다.

waitpid()는 WNOHANG에 의해서 어떤자식도 죽은적이 없다면 0을 종료된 자식의 프로세스 ID가 에러종료이면 -1을 반환하기 때문입니다.

또한 정상적인 종료가 아닌지를 판단하기 위해서 WIFSIGNALED()매크로를 이용해서 검사해주는 것도 필요하지요. 나머지는 대부분 WIFEXITED()매크로에 검출되니까 별 문제는 없습니다.

PS) 시그널핸들러의 블럭킹은 조금 다른 문제입니다. 기본적으로 시그널핸들러는 시그널을 블럭하지 않습니다. 시그널을 블럭하느냐 마느냐는 sigset_t 형의 매스크를 만들어서 블록을 하는가에 따르기 때문입니다.

========================================
* The truth will set you free.

sunyzero의 이미지

signal()보단 sigaction()을 쓰기를 권장합니다.

signal()함수는 머신에 따라서 일회적으로 사용되고 핸들러가 재설정되기도 합니다. 따라서 정확한 시그널 핸들링을 위해서는 sigaction()을 쓰기를 권장합니다.

========================================
* The truth will set you free.

ulra의 이미지

좋은 하루 되세요. :)

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

vness의 이미지

sunyzero님 답변 감사합니다.

기본적으로 시그널핸들러는 시그널을 블럭하지 않습니다. 
시그널을 블럭하느냐 마느냐는 sigset_t 형의 매스크를 만들어서 블록을 하는가에 따르기 때문입니다.

테스트 한 결과..

implemetation 마다 다른 것 같군요.

linux와 SunOs도 다른 것 같습니다.

vness의 이미지

waitpid()는 WNOHANG에 의해서 어떤자식도 죽은적이 없다면 0을 종료된 자식의 
프로세스 ID가 에러종료이면 -1을 반환하기 때문입니다.

어떤 자식이 죽은적이 없다면 0을 리턴하는 것이 아니라 어떠한 child process도 남아있지 않다면 0을 리턴하는 걸로 알고 있는데요.

따라서 보통..

SIGCHLD가 폭주할 경우에..

while(waitpid(-1, NULL, WNOHANG) > 0);

으로 처리하는 것으로 알고 있습니다.

댓글 달기

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