waitpid 에 관련 하여...

yoonbs의 이미지

여러가지로 많은 정보를 얻고 있습니다.

waitpid 관련 하여 여쭈어 볼려구여....

먼저 특정 시간을 스케줄링을 하여 순차적으로 fork 시키는 스케줄러를 만들었습니다.
프로세스 동기화 때문에 꼭 선행된 프로세서가 끝나야만 다음 프로 세스가 돌아가게 했는데 waitpid 를 거치지 않고 다음 프로세서가 실생되어 도는 문제가 발생 하였습니다.

프로그램 로직은 대략 이렇습니다.

int main(int argc, char *argv[]) {
.......

signal(SIGCHLD,sigchld_handler);
signal(SIGHUP,SIG_IGN);
#ifdef SIGTTOU
signal(SIGTTOU,SIG_IGN);
#endif
signal(SIGTTIN,SIG_IGN);

while ( 1 ) {

'''''''''''''''

if (시간 check 조건) {

if ((child1 = fork()) == 0) /* child1 */
execl((char *) "실행파일 디렉토리", (char *) "실행파일1", char *) "Option", (char *) 0);

if ((child2 = fork()) == 0) /* child2 */
execl((char *) "실행파일 디렉토리", (char *) "실행파일2", char *) "Option", (char *) 0);

waitpid(child1, &status, NULL);
waitpid(child2, &status, NULL);

if ((child3 = fork()) == 0) /* child3 */
execl((char *) "실행파일 디렉토리", (char *) "실행파일3", char *) "Option", (char *) 0);

''''''''''''''''''
} /* end if */

''''''''''''''''''
} /* end while */

''''''''''''''''''
}

제가 생각 하기에 이런 로직이라면 child1 과 child2 가 waitpid 에서 끝나는걸 기다렸다가 child3 을 수행 하는 것으로 알고 있습니다.
헌데 child1 또는 child2 가 끝나지 않은 상태에서 child3 이 돌구 있는 상황이 벌어 졌습니다. 왜 이런 일이 일어나는지 모르겠거덩요 ..
첨에는 sig_handler 와 waitpid를 같이 쓰는 문제가 아닐까 생각 했었는데 그렇다는 구체적인 이유를 찿지 못했습니다.
하나 더 궁금한건 waitpid 의 리턴값을 찍어 봤더니 "-1" 이 나오더라구여
이게 정상인지 아닌지 모르겠습니다 참고로 waitpid 의 첫번째 아규먼트인 child 프로세서의 pid 는 정상으로 찍혔었습니다. child 프로세서의 pid 가 -1 이 아닌 정상값으로 넘어 갔는데 waitpid 값이 -1 이나는게 정상인지 아닌지 모르겠습니다.
고수님들의 조언 부탁 드립니다.

stoneshim의 이미지

일단 os의 종류와 버전을 명시해 주시면 좋겠습니다.
os 마다 signal에 대한 방식이 조금씩 다를 수 있습니다.

그리고 waitpid()에서 -1 return이라면 뭔가 잘못된 것입니다.
perror()로 오류의 내용을 출력해 주세요.

우리 모두 리얼리스트가 되자. 그러나 가슴에 이룰 수 없는 꿈을 가지자

yoonbs의 이미지

- 먼저 프로세스가 돌고 있는 OS 의 version 은
Sun OS 5.7 과 5.8 입니다.

기본적으로 올린 소스는 Child 프로세서를 2개가 실행 시키고 그걸 그다렸다가
1개의 child를 포크 시킨것으로 올렸지만 실제로는 2개를 실행시키고,
그것이 끝난 다음 2개의 프로세서를 포크시키는 로직 입니다.

- perror 의 메세지 입니다. perror 는 waitpid 한다음 찍어 봤구여..

Error Msg: Interrupted system call <- child1 을 waitpid 후 찍은 에러
Error Msg: Interrupted system call <- child2 을 waitpid 후 찍은 에러
Error Msg: Interrupted system call <- child3 을 waitpid 후 찍은 에러
Error Msg: No child processes <- child4 을 waitpid 후 찍은 에러

- 다음은 handler 에서 찍은 메세지 입니다.
> child 537 terminated
> WIFEXITED(stat) is non zero(normal exit).
> child 680 terminated
> WIFEXITED(stat) is non zero(normal exit).
> child 743 terminated
> WIFEXITED(stat) is non zero(normal exit).
> child 673 terminated
> WIFEXITED(stat) is non zero(normal exit).

혹시 해서 handler 의 소스도 올립니다.
============================================
void sigchld_handler() {

int stat, res;
pid_t pid;

signal(SIGCHLD, sigchld_handler);

while ( ( pid = waitpid( -1 , &stat , WNOHANG ) ) > 0 )
printf("> child %d terminated\n", pid);

if((res = WIFEXITED(stat)) != 0)
printf("> WIFEXITED(stat) is non zero(normal exit). \n");

return;
}
=============================================

stoneshim의 이미지

지금 문제는 main, sigchld_handler양쪽에서 모두 waitpid()를 호출하는것이 문제로 보입니다.

한쪽에서만 사용하시면 될것 같네요.

sigchld_handler에서만 waitpid하시려면

/* 전역변수 - wait 할 child process 수 */
int wait_chldcnt = 2;

...

void sigchld_handler(int signo) {

....
  if( signo == SIGCHLD ) {
    wait_chldcnt--;
    ....
    waitpid()...
  }
...
}


main()
{
....


/* waitpid() 대신 */
    while(1) {
        if( wait_chldcnt <= 0 )
           break;
        sleep(100);
    }

/*    fork child3 */
     ...


}

이런식으로 하시구요.

main에서만 하실 거라면... sigchld_handler에서는 waitpid 함수를 사용하지 마시고, main에서만 사용하시면 될겁니다. 이때 다음처럼 사용하시는게 안전해 보이네요...

while(1) {
    ret = waitpid(child1, &status, NULL); 
    if( ret < 0  && errno == EINT ) continue;
    else break;
}

우리 모두 리얼리스트가 되자. 그러나 가슴에 이룰 수 없는 꿈을 가지자

stoneshim의 이미지

첨언하면 요즘엔 signal()보다는 sigaction()을 많이 사용합니다.

signal()은 해당 signal이 발생했을때 해당 signal에 대한 action을 SIG_DFL로 바꾸기 때문에 sighandler에서 다시 signal()을 호출하는데 sigaction()은 한번 설정으로 그 값이 바뀌지 않습니다.

Linux에서도 signal()이 위와 같다고 manpage에 나와있는데 제가 작업하는 환경에서는 signal()이 sigaction()과 동일하게 작동하더군요...

어쨌든 요즘엔 signal() 보다 sigaction()을 많이 사용합니다.

우리 모두 리얼리스트가 되자. 그러나 가슴에 이룰 수 없는 꿈을 가지자

yoonbs의 이미지

좋은 말씀 감사함다..

도움이 많이 되었습니다. 꾸뻑 ^&^ ...

xfmulder의 이미지

해결되셨다니 다행입니다.

waitpid() 연산자체가 다른 CHILD 의 중지로 SIGCHLD 를 받아 중지되고 waitpid() < 0 면서 errno == EINTR 로 되었기 때문인것 같습니다.
waitpid() 명령은 특정 CHILD 만을 기다리는 함수로 쓰이기는 하나, 해당 CHILD 를 기다리는 도중에 SIGCHLD 가 발생해서 시그널핸들러로 점프했다가 처리하고 나서 되돌아왔고 이때 errrno == EINTR 로 설정된 듯합니다.
즉, 기다리고자 하는 CHILD 를 처리하고 나서 정상적으로 return 한게 아니기 때문입니다.

내 자식들도 나처럼 !!

댓글 달기

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