web-dev-qa-db-ja.com

Linuxでパイプを閉じる必要があるのはなぜですか?

プロセス間通信にパイプを使用する場合、パイプの一端を閉じる目的は何ですか?

例: パイプを使用して2つのプログラム間で単純な文字列を送信する方法

パイプの片側が子プロセスと親プロセスで閉じていることに注意してください。なぜこれが必要なのですか?

27
pghazanfari

パイプを使用して2つのプロセス(親と子)を接続する場合は、フォークの前にパイプを作成します。

フォークは、両方のプロセスがパイプの両端にアクセスできるようにします。これは望ましくありません。

読み取り側は、EOF状態に気付いた場合にライターが終了したことを知るはずです。これは、すべての書き込み側が閉じている場合にのみ発生します。そのため、書き込みFD ASAPを閉じることが最善です。 。

ライターは、開いているFDが多すぎて、おそらく存在する可能性のある開いているFDの制限に達しないようにするために、読み取りFDを閉じる必要があります。その上、そのとき唯一のリーダーが死んだ場合、ライターはSIGPIPEまたは少なくともEPIPEエラー(シグナルの定義方法によって異なる)を受け取ることによってこれについて通知されます。リーダーが複数ある場合、ライターは「本物」が消えたことを検知できず、書き込みを続け、書き込みFDがブロックすることを期待してスタックし、「未使用」のリーダーが何かを読み取ります。

だからここで詳細に何が起こるか:

  • 親プロセスはpipe()を呼び出し、2つのファイル記述子を取得します。それをrdwrと呼びましょう。
  • 親プロセスはfork()を呼び出します。これで、両方のプロセスにrdwrがあります。
  • 子プロセスがリーダーであると想定します。

    その後

    • 親はその読み取り端を閉じる必要があります(FDを無駄にしないため、および死にかけているリーダーを適切に検出するため)。
    • 子は書き込み側を閉じる必要があります(EOF状態を検出できるようにするため)。
39
glglgl

一度に開くことができるファイル記述子の数には制限があります。パイプを開いたままにし、すぐに閉じない場合、FDが不足し、何も開くことができなくなります。パイプではなく、ファイルでもソケットでもありません...

パイプを閉じることが重要になるもう1つの理由は、閉じること自体がアプリケーションにとって意味がある場合です。たとえば、パイプの一般的な使用法は、errnoforkを使用して子プロセスから親にexecを送信することです 外部プログラムを起動します

  1. 親はパイプを作成し、forkを呼び出して子プロセスを作成し、その書き込み端を閉じて、パイプからの読み取りを試みます。
  2. 子プロセスはexecを使用して別のプログラムを実行しようとします:
    1. プログラムが存在しないなどの理由でexecが失敗した場合、子はerrnoをパイプに書き込み、親はそれを読み取り、何が問題だったかを認識し、ユーザーに知らせることができます。
    2. execが成功すると、何も書き込まれずにパイプが閉じます。親のread関数は、パイプが閉じられ、プログラムが正常に開始されたことを示す0を返します。

親がパイプからの読み取りを試みる前にパイプの書き込み側を閉じなかった場合、readが成功したときにexec関数が戻らないため、これは機能しません。

5
Joni