5

フォーク (プロセス)、シグナル、および選択を使用してデータを処理する (円周率を計算する) プログラムを作成する課題に取り組んでいます。

私は現在シグナルに取り組んでおり、私がやりたいと思うのは SIGPIPE を使用することです。プログラムがそれをキャッチすると、パイプに再度書き込もうとします(プロセスがリーダーのないパイプに書き込もうとした場合、SIGPIPE が送信されます)。

main() で fork() を使用して、ワーカー関数に送信することで各プロセスに同じ作業を割り当てます。

void worker(int id) {
    .... (this piece of code is not relevant)

    if(write(pfd[id][1], &c, sizeof(c)) == -1)
        printf("Error occurred: %s\n",strerror(errno));

}

この関数にシグナルを実装して SIGPIPE をキャッチし、再びパイプに書き込むにはどうすればよいですか?

ありがとうございました!

4

1 に答える 1

11

通常、キャッチする代わりにSIGPIPEそれを無視します。これにより、プログラムが黙って終了する代わりにwrite失敗します。EPIPE

ただし、パイプへの書き込み時にエラーが発生するSIGPIPE場合は、再試行しないでください。それは決してうまくいきません。 SIGPIPEは、パイプにリーダーがないことを意味します。現在、パイプにリーダーがない場合、リーダーはありません。(このように考えてみてください: リーダーのないパイプはどのようにしてリーダーを取得するのでしょうか? それは不可能です!)

あなたの問題は、パイプのもう一方の端を閉じていることです。それを修正し、心配しないでくださいSIGPIPESIGPIPE症状だけです。

編集:ここで答える質問が 2 つあります。これらの質問の両方に答えられない場合は、処理を気にしないでくださいSIGPIPE

  1. 私のプログラムが受け取る原因は何SIGPIPEですか? 受信する唯一の方法SIGPIPEは、パイプの読み取り側を閉じることです。これは、読み取りプロセスがクラッシュした場合、またはパイプを閉じるようにプログラムされている場合に発生します。ネットワーク サーバーを作成している場合、または未知のプロセスと通信している場合、これはよくあることです。ただし、両方のプログラムを作成し、両方ともローカルで実行する場合は、プログラミング エラーを示している可能性があります。

  2. をキャッチしたとき、私のプログラムは何をしSIGPIPEますか? パイプを使用してサーバーと通信するクライアント プロセスを作成している場合、何をすべきSIGPIPEでしょうか? 再試行することはできません。通常、クライアントは接続先のサーバーを再起動できません。賢明なデフォルトのことをしてSIGPIPE、プログラムを終了させて​​ください。ただし、サーバーがクライアントにデータを送信している場合、サーバーが制御して取得すると、クライアントが再起動SIGPIPEする可能性があります。しかし、これは非常に悪い考えかもしれません。たとえば、クライアントが決定論的である場合、クライアントは再びクラッシュするだけであり、単純なクラッシュではなく無限ループに陥ります。

したがって、ここでの一般的な格言は、「処理する準備ができているエラーのみをキャッチする」です。完全を期すためだけにエラーをキャッチしないでください。プログラムをクラッシュさせたり、操作を失敗させたりするだけで、後で戻ってデバッグできます。

コード スニペット:これは、私のプロジェクトの 1 つからのコード スニペットです。実行しても、SIGPIPEプロセスは終了しません。代わりにwrite、エラーが生成されEPIPEます。ネットワークサーバーを作成している場合EPIPE、クライアントが突然切断される可能性のある方法の 1 つです。

void
ignore_sigpipe(void)
{
    struct sigaction act;
    int r;
    memset(&act, 0, sizeof(act));
    act.sa_handler = SIG_IGN;
    act.sa_flags = SA_RESTART;
    r = sigaction(SIGPIPE, &act, NULL);
    if (r)
        err(1, "sigaction");
}
于 2011-10-15T12:19:35.403 に答える