パイプのもう一方の端を密封してください。

パイプのもう一方の端を密封してください。

私は以下を使用してIPC用のコードを書きましたpipe()

#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
    
    
int main(void) {
    char message_buffer[15] = "Hello World \n";  
    char read_buffer[15];
    int fd[2]; 
   
    int return_value = pipe(fd);
   
    if (return_value < 0) {
        printf("Error creating the pipe");
    }
    
    int rc = fork();
    if (rc  < 0) {
        printf("Error forking a child");
    }
    
    if (rc > 0) {
        close(fd[0]);
        write(fd[1], message_buffer, 15);
        close(fd[1]);
        wait(NULL);
    } else {
        close(fd[1]);
        read(fd[0], read_buffer, 15);
        close(fd[0]);
        printf("The Message: %s", read_buffer);
    }

    return 0;
}

配管に初めて接するのに、次のような質問があります。

  1. なぜ親が書く前に読んでいる側を閉じ、書いた後に書く側を閉じなければならないのかわかりませんか?
  2. 子供も同じですが、読む前に書き込み側を閉じる必要があるのはなぜですか。
  3. 親プロセスと子プロセスが同時に実行されているので、親プロセスがメッセージを書き込んでいる間に子プロセスがメッセージを読み取るとどうなりますか?
  4. 親と子が同時に実行されているので、子が読んで親がまだパイプに何も書いていない場合はどうなりますか?

私の質問は愚かなようですが、コース試験のために一般的な配管を勉強しているので、答えを助けてください。

ベストアンサー1

正解は質問1と2内部にpipe マニュアルページ(「はい」セクション):

分岐後、各プロセスはパイプに不要なファイル記述子を閉じます(pipe(7)を参照)。

パイプは一方向なので、端が指定されています。読む終わり書く終わり。親がこのパイプを使用して子にデータを書き込む場合、親は読み取り側を開いたままにする必要はありません。対照的に、子プロセスがパイプからデータを読み取ろうとすると、書き込み側を開く必要はありません。

しかし、一つもっと重要な理由パイプの不要な端部を閉じるために使用されます。説明する@ilkkachu ユーザーが作成しました。リンクされた回答を参照してください。

編集する:

なぜ両親は文章を書いた後に書く側を閉じなければならないのか、子供はなぜ読んだ後に読んだ方を閉じるべきか尋ねました。

彼らはこれを行う必要はありません。両方のプログラムがパイプを使用して引き続き実行され、データを交換するにはパイプを開いたままにする必要があります。パイプの使用を示し、メッセージの送信後に終了する単純なサンプルプログラムでは、親プロセスと子プロセスは、プログラムが終了する前にリソースを適切にクリーンアップするためにパイプファイル記述子を閉じることができます。

質問#3と#4への答えは次のとおりです。pipe(7) マニュアルページ

あなたの質問#3:

親プロセスと子プロセスを同時に実行できるため、親プロセスがメッセージを書き込んでいる間に子プロセスがメッセージを読み取るとどうなりますか?

子は、親によって作成されたパイプで利用可能なすべてのデータを読み取ることができます。マニュアルページによると:

POSIX.1 は、PIPE_BUF バイトより小さい書き込みはアトミックでなければならないことを指定します。出力データは連続シーケンスでパイプに書き込まれます。 PIPE_BUF バイトを超える書き込みは非原子的である可能性があります。カーネルは、データを他のプロセスによって書き込まれたデータとインターリーブできます。 POSIX.1では、PIPE_BUFは512バイト以上でなければなりません。 (Linuxでは、PIPE_BUFは4096バイトです。)

あなたの質問#4:

親と子を同時に実行できるので、子が読み取られ、親がまだパイプに何も書いていない場合はどうなりますか?

マニュアルページには次のように記載されています。

プロセスが空のパイプからデータを読み取ろうとすると、read(2)はデータが利用可能になるまでブロックされます。プロセスがパイプ全体(以下を参照)に書き込みを試みると、書き込みが完了するのに十分なデータがパイプから読み取られるまでwrite(2)がブロックされます。

コメントの質問に答えてください。

質問 1 と 2 の場合、不要な端を閉じないとプログラムに影響はありません。

パイプラインの動作を妨げてはいけませんが、プログラムが使用するリソースには少しスペースがかかります。パイプの不要な端を閉じても、これらのリソースは保持されません。

質問3の場合、これは親が書いた内容を子供が読むことを意味します。両親が書くべきことを完了したことを子供はどうやって知ることができますか?

マニュアルページには次のように記載されています。

パイプが提供する通信チャネルはバイトストリームです。メッセージ境界の概念はありません。

これは、パイプが送信するデータに興味がないことを意味します。 「メッセージ」が何を意味するのか、親が書き込みを終えたのか、さらに多くのデータを書きたいかどうかもわかりません。

「完全なメッセージ」が何であるかを判断するには、独自の技術を実装する必要があります。たとえば、親は\0特殊文字(パイプが使用される特定のコンテキストで意味のある他の文字)を送信して、完全なメッセージが作成されたことを子に指示できます。

おすすめ記事