0

信号の処理方法を学ぼうとしています。私のプログラムには、以前に作成されたサブプロセスの pid の配列があります。いいえ、数秒ごとに sigtstp シグナルをそれらの 1 つに送信したいと思います。親プロセスに sigchld を送信して終了するだけです。親プロセスは、終了したプロセスの終了コードを出力し、終了したプロセスの代わりに次のプロセスを作成する必要があります。最初のループではすべて正常に動作しますが、2 番目のループではハングします。したがって、出力で次を取得します。

loop
slept
forking
in to array
loop
Zakonczyl sie potomek 3934 z kodem 0.

そのため、スリープは最初のループでは機能しますが、2 番目のループでは機能しないようです。または、シグナルを処理した後にメインプロセスが制御を戻さなかったが、これは発生しないはずです。したがって、ここで何が間違っているのかわかりません。

while(1) {
                printf("loop\n");
                sleep(5);
                printf("slept\n");
                int r = rand() % n;
                if(kill(process_tab[r],SIGTSTP) < 0) {
                        printf("Error while sending sigtstp signal.\n");
                } else {
                        printf("forking\n");
                        if((child = fork()) < 0) {
                                printf("Fork failed.\n");
                        } else if(child == 0) {//to sie dzieje w procesie
                                if(signal(SIGTSTP,&catch_sigtstp)) {
                                        printf("Error while setting signal handler.\n");
                                        _exit(EXIT_FAILURE);
                                }
                                while(1) {
                                }
                        } else { //to sie dzieje w parencie
                                process_tab[r] = child;
                                printf("in to array\n");
                        }
                }
}

そして、ここにハンドラーがあります。

void catch_sigtstp(int signal) {
        kill(ppid,SIGCHLD);
        _exit(EXIT_SUCCESS);
}

void catch_sigchld (int signal) {
        int status;
        pid_t child = wait(&status);
        printf("Zakonczyl sie potomek %d z kodem %d.\n",child,status);
}
4

1 に答える 1

2

fflushの後に追加しprintfます。

printf("Something\n");
fflush(stdout);

stdioそうしないと、デフォルトでバッファリングされるように出力が得られない場合があります。

編集:ハンドラーの問題

printf関数は再入可能ではないため、シグナル ハンドラで関数を使用するのは非常に安全ではありません。また、catch_sigchild関数は次のように変更できます。

void catch_sigchld (int signal) {
    int status;
    pid_t child;

    while ((child = waitpid(-1, &status, WNOHANG)) > 0)
    {
       // may be something else?
       // ...printf("Zakonczyl sie potomek %d z kodem %d.\n",child,status); 
    }
}   

その理由は、1 つのシグナルが複数の死亡した子に対して配信される可能性があるためです。

編集:印刷時に信号をブロックします。

stdio 内のデッドロックを回避するには、シグナルをブロックする必要があります。

sigset_t set;

sigemptyset(&set);
sigaddset(&set, SIGCHILD);

...
sigprocmask(SIG_BLOCK, &set, NULL);
printf("my output");
sigprocmask(SIG_UNBLOCK, &set, NULL);
...

編集: @Barmar が指摘したように、親プロセスは SIGCHILD シグナルを 2 回受け取ります。1 回は子のシグナル ハンドラーから、もう 1 つは OS からです。

修正するには、独自の信号ソースを削除するだけで十分な場合があります。

void catch_sigtstp(int signal) {
    // kill(ppid,SIGCHLD); //< This one causes two signals per one child
    _exit(EXIT_SUCCESS);
}
于 2013-05-02T19:52:58.033 に答える