2017-04-25 9 views
1

私はフォーク5回呼び出していますので、私は合計5子プロセスと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; 
} 

を持っています。このコードを実行すると、この出力が得られます

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を2回見ているのか分かりません。すべての反復で増分しているので、私は重複があってはいけません。

なぜ私はchild3を2回見ているのですか?

+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を呼び出すことは未定義の動作です。シグナルハンドラ中に安全であることが保証されている関数のリストは、ほんのわずかです。

これを削除すると、シグナルハンドラの外側にあるものが予期しない動作をすることはありません。

+0

ハンドラではなくメインのコードで予期しない動作が発生しています。作成された子プロセスは親プロセスからのものです。 – Dude

+0

症状がどこに表示されるかは関係ありません。 – covener

1

stdioバッファの状態は、プロセスのメモリ空間に格納されます。フォーク時にバッファが空でない場合、親と子は両方とも、"Child process 3\n"がフラッシュされるのを待っているstdoutバッファにあるという情報のコピーを持っています。

そして、彼らは結局それをフラッシュします。

これは、子プロセスでexitの代わりに_exitを呼び出すことで回避できます。 exitは、作成されてから正常なexecを完了していないプロセスにいるときには、通常は悪い考えです。

関連する問題