2017-04-25 7 views
1

나는이 C 코드포크가이 c 프로그램에 대해 잘못된 출력을 생성합니까?

/* SIGCHLD handler. */ 
static void sigchld_hdl (int sig) 
{ 
    /* Wait for all dead processes. 
    * We use a non-blocking call to be sure this signal handler will not 
    * block if a child was cleaned up in another part of the program. */ 
    //printf("Inside handler: \n"); 
    while (waitpid(-1, NULL, WNOHANG) > 0) { 
     printf("reaped\n"); 
    } 
    //printf("Outside handler: \n"); 

} 

int main (int argc, char *argv[]) 
{ 
    struct sigaction act; 
    int i; 

    memset (&act, 0, sizeof(act)); 
    act.sa_handler = sigchld_hdl; 

    if (sigaction(SIGCHLD, &act, 0)) { 
     perror ("sigaction"); 
     return 1; 
    } 

    /* Make some children. */ 
    for (i = 0; i < 5; i++) { 
     switch (fork()) { 
      case -1: 
       perror ("fork"); 
       return 1; 
      case 0: 
       exit(0); 
       return 0; 
      default: 
       //printf("inside parent\n"); 
       printf("Created child %d\n", i); 

     } 
    } 

    /* Wait until we get a sleep() call that is not interrupted by a signal. */ 
    while (sleep(1)) { 
     printf("inside parent while loop\n"); 
    } 

    return 0; 
} 

나는 포크 5 회를 호출하고, 그래서 나는 총 5 자식 프로세스 및 한 부모 프로세스를 기대합니다. 이 코드를 실행하면이 출력이 표시됩니다.

Created child 0 
Created child 1 
reaped 
reaped 
Created child 2 
Created child 3 
Created child 3 
reaped 
reaped 
Created child 4 
reaped 
inside parent while loop 

왜 나는 child3가 두 번 보게되는지 알 수 없습니다. 모든 반복에서 점차 증가하고 있으므로 i와 관련하여 중복이 없어야합니다.

누군가 내가 왜 child3을 두 번 보는지 설명 할 수 있습니까?

+1

재현 할 수 없습니다. 당신은 시그널 핸들러에서'printf()'를 호출하면 안된다. 아마 그게 문제 일 것이다. – Barmar

+0

@Barmar 왜 핸들러에서 printf를 호출하면 안됩니까? 재생산하려면 몇 번 실행해야합니다. – Dude

+1

비동기 안전하지 않습니다. http://stackoverflow.com/questions/16891019/how-to-avoid-using-printf-in-a-signal-handler – Barmar

답변

0

문제는 디버깅 출력입니다. 비동기 신호 핸들러에서 printf를 호출하는 것은 정의되지 않은 동작입니다. 시그널 핸들러 (signal handler) 동안 안전하다는 보장 된 함수의 짧은 목록 만있다.

제거하면 신호 처리기 외부에 예기치 않은 동작이 발생하지 않습니다.

+0

처리기가 아니라 주 코드의 예기치 않은 동작이 나타납니다. 생성 된 하위 프로세스는 상위 프로세스 x에서 왔습니다. – Dude

+0

증상이 나타나는 위치는 중요하지 않습니다. – covener

1

stdio 버퍼의 상태는 프로세스의 메모리 공간에 포함됩니다. 포크시 버퍼가 비어 있지 않으면 부모와 자식 모두 플러시를 기다리는 stdout 버퍼에있는 "Child process 3\n"이라는 정보 사본을 가지고 있습니다.

그리고 결국 둘 다 플러시됩니다.

자식 프로세스에서 exit 대신 _exit을 호출하면이 문제를 방지 할 수 있습니다. exit은 일반적으로 프로세스가 성공적으로 완료되지 않은 프로세스에있을 때 발생합니다.