0

いくつかのサブプロセスを実行し、その出力を読み取る必要があるツールキットのモジュールを作成しています。ただし、ツールキットを使用するメイン プログラムは、いくつかのサブ プロセスを生成し、ゾンビ プロセスを取り除くためのSIGCHLD呼び出しを行うシグナル ハンドラを設定することもあります。wait(NULL)その結果、作成したサブプロセスが my 内で終了waitpid()すると、シグナル ハンドラが呼び出される前に子プロセスが処理されるため、wait()シグナル ハンドラ内の は次のプロセスが終了するまで待機します (これには永遠にかかる可能性があります)。Linux の実装ではファミリwait()SIGCHLD. 私は試してみましpopen()posix_spawn()両方とも同じ問題を抱えています。また、直接の子がすぐに存在するように double を使用しようとしましたが、受信後に呼び出されるfork()ことはまだ保証できません。waitpid()SIGCHLD

私の質問は、プログラムの他の部分が呼び出すシグナルハンドラーをセットアップする場合wait()(おそらく呼び出す必要がありますが、それは私が制御できるものではありません)、ハンドラーwaidpidを上書きせずに子プロセスを安全に実行する方法はありますか(SIGCHLD一部のプログラムでは便利です)またはゾンビプロセス。

問題を示す小さなプログラムは次のとおりです (メイン プログラムは、waitpid() で直接待機している短いプログラムではなく、長期的な子プログラムの終了後にのみ終了することに注意してください):

#include <signal.h>
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

static void
signalHandler(int sig)
{
    printf("%s: %d\n", __func__, sig);
    int status;
    int ret = waitpid(-1, &status, 0);
    printf("%s, ret: %d, status: %d\n", __func__, ret, status);
}

int
main()
{
    struct sigaction sig_act;
    memset(&sig_act, 0, sizeof(sig_act));
    sig_act.sa_handler = signalHandler;
    sigaction(SIGCHLD, &sig_act, NULL);

    if (!fork()) {
        sleep(20);
        printf("%s: long run child %d exit.\n", __func__, getpid());
        _exit(0);
    }

    pid_t pid = fork();
    if (!pid) {
        sleep(4);
        printf("%s: %d exit.\n", __func__, getpid());
        _exit(0);
    }
    printf("%s: %d -> %d\n", __func__, getpid(), pid);

    sleep(1);
    printf("%s, start waiting for %d\n", __func__, pid);
    int status;
    int ret = waitpid(pid, &status, 0);
    printf("%s, ret: %d, pid: %d, status: %d\n", __func__, ret, pid, status);

    return 0;
}
4

1 に答える 1

0

プロセスがシングルスレッドの場合は、(sigprocmask を使用して) CHLD シグナルを一時的にブロックし、fork/waitpid してから、再度ブロック解除できます。

fork された子でシグナルのブロックを解除することを忘れないでください。POSIX では、プロセスの開始時にシグナル マスクは未定義であると述べられていますが、ほとんどの既存のプログラムでは、シグナル マスクが完全に未設定であると想定されています。

于 2015-01-17T20:41:12.943 に答える