0

man ページにsystem() 、「コマンドの実行中に SIGCHLD がブロックされる」と記載され
ています。私のコードではSIGCHLD、ログに何かを書き込み、シグナルを無視するためのハンドラをインストールしています。これは、ログで終了した子について知り、ゾンビ プロセスを回避するために行います。

コールを使用すると問題が発生しsystem()ます。このハンドラーを配置すると、子の終了コードではなく、system()常に戻ります。-1しかし、マニュアルページからの上記の引用によるとsystem()、子からのシグナルを処理することになっています。

私は何を間違っていますか?

私のコードは次のとおりです。

static void handleSignal(int signum, siginfo_t* inf, void* ctx) {
    cout << "in signal " << signum << endl;
}

int main() {
    struct sigaction chldsa, prevchld;
    chldsa.sa_sigaction = &handleSignal;
    sigemptyset(&chldsa.sa_mask);
    chldsa.sa_flags = SA_SIGINFO | SA_RESTART | SA_NOCLDSTOP | SA_NOCLDWAIT;
    if (sigaction(SIGCHLD, &chldsa, &prevchld) == -1) {
        cout << "Failed setting sigaction SIGCHLD " << errno;
    }

    int x = system("exit 1");
    cout << "RET=" << x << endl;
}
4

2 に答える 2

3

とその影響のみを取り除きたい場合は、代わりにハンドラの最後SA_NOCLDWAITすべての子を取得します。SIGCHLD

追加するために編集:次のことを確認しました:

    pid_t p;

    /* Reap all pending child processes */
    do {
        p = waitpid(-1, NULL, WNOHANG);
    } while (p != (pid_t)0 && p != (pid_t)-1);

SIGCHLDハンドラー (インストール済み)で最後に実行すると正常に動作しSA_NOCLDSTOP |SA_RESTART | SA_SIGINFOます。ゾンビはなくsystem()、正しい終了ステータスを返します。

これwaitpid()は、POSIX.1-2004 による Linuxのasync-signal safeWNOHANG関数であり、呼び出しがブロックされないことを意味するため、上記のループは安全です。

ただし、標準シグナルはキューに入れられないため、2 つ以上のプロセスが適切なタイミングで終了した場合、親プロセスで子のリーピング ループが実行された直後で、シグナル ハンドラが戻る前に 1 つのプロセスが終了する可能性があります。より多くの子供たちがすぐに刈り取られるわけではありません。ただし、次の子プロセスが終了すると、それらは終了します。これを軽減するには、プログラムの通常の操作の一部として、またはタイマー割り込みを介して、上記のループを定期的に実行する必要があります。ループがブロックされることはなく、消費される CPU 時間はごくわずかです。

生きている子がwaitpid(-1, NULL, WNOHANG)いる場合は 0 を返し、生きている子がいない場合は 0 を返すか、リープされたばかりのプロセスのプロセス ID を返すことに注意してください。(必要に応じて、NULL 以外のステータス ポインターを使用して、終了した各子の終了ステータスをキャプチャし、ログに記録することで、ログにループを利用できます。定期的なタイマーを同じシグナル ハンドラーにフックすることもできます。 、 例えば。)-1errno == ECHILD

于 2013-07-09T10:06:43.873 に答える