1

ループ内に 4 つの子プロセスを作成する C プログラム (FreeBSD、Unix 用) を作成しようとしています。それぞれの子供は何かをし、死ぬとすぐに他の子供に取って代わられます。というわけで、4人の子供がずっと働いています。

各子 PID をテーブルに登録する必要があり、それらが終了した後、テーブルの PID を削除する必要があります。これは私が問題を抱えている部分です。

したがって、最初の試行では、死んだ子の PID をグローバル変数に送信するハンドラーを作成しようとしました。

int global_variable;

void handler_SIGCHLD(int sig)
{
    pid_t son;
    int e;

    do {
        son = wait3(&e, WNOHANG, NULL);
        if ((son > (pid_t)0) && (WIFEXITED(e) || WIFSIGNALED(e)))
        {
            global_variable = son;
        }
    } while (son > (pid_t)0);
}

次に、親でそれを使用して、死んだ子の PID をテーブルから削除します。しかし、2 人の子供が同時に死亡した場合、PID の 1 つが別の PID によって上書きされることに気付きました。

どうすればこの状況を回避できますか?

4

1 に答える 1

2

シグナルハンドラからこれを行うべきではありません。シグナルハンドラーから何もするべきではありません (正気を保ちたい場合)。

信頼できる方法は、シグナルをファイル記述子イベントに変換し、イベント ループ ( 、、...)SIGCHLDに統合することです。イベントを監視するときは、in ループを使用して、死亡したすべての子を収集します。ここで私の答えの詳細を参照してください: https://stackoverflow.com/a/8398491/1020667selectpollepollwaitpid(..., WNOHANG)

上記の回答は、Linux を使用していて、signalfd(Linux 固有の機能) を使用してシグナルをファイル記述子に変換することを前提としています。ただし、代わりに、「セルフパイプ」トリック (細心の注意を払って) またはkqueue(FreeBSD、OSX) を使用できます。では、中間ファイル記述子がないことに注意してくださいkqueue。ファイル記述子イベントと同様に、シグナル イベントを直接受け取ります。

一方、移植可能なイベント ループ ライブラリを使用すると、これらすべての低レベルの詳細を回避できます。一部のライブラリでは、子プロセスを開始および監視するための機能がすでに提供されています。libuv(node.jsの)をお勧めします。

于 2014-11-09T11:18:01.060 に答える