Inter-process-communication-pipes

提供:Dev Guides
移動先:案内検索

プロセス間通信-パイプ

パイプは、2つ以上の関連プロセスまたは相互関連プロセス間の通信媒体です。 1つのプロセス内、または子プロセスと親プロセス間の通信のいずれかです。 コミュニケーションは、親、子、孫などの間のコミュニケーションなど、マルチレベルにすることもできます。 通信は、1つのプロセスがパイプに書き込み、他のプロセスがパイプから読み取ることによって実現されます。 パイプシステムコールを実現するには、ファイルに書き込むファイルとファイルから読み取るファイルの2つのファイルを作成します。

パイプ機構は、パイプで水をバケツなどの容器に入れたり、誰かがマグカップで水を取り出すなどのリアルタイムのシナリオで見ることができます。 充填プロセスはパイプへの書き込みに過ぎず、読み取りプロセスはパイプからの取得に他なりません。 これは、一方の出力(水)が他方(バケット)の入力であることを意味します。

1つのパイプ

#include<unistd.h>

int pipe(int pipedes[2]);

このシステムコールは、一方向通信用のパイプを作成します。つまり、2つの記述子を作成します。1つはパイプからの読み取りに接続され、もう1つはパイプへの書き込みに接続されます。

記述子pipedes [0]は読み取り用、pipedes [1]は書き込み用です。 pipedes [1]に書き込まれたものはすべてpipedes [0]から読み取ることができます。

この呼び出しは、成功すると0を返し、失敗すると-1を返します。 失敗の原因を知るには、errno変数またはperror()関数で確認してください。

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

ファイルの基本的な操作は読み取りと書き込みですが、操作を実行する前にファイルを開き、必要な操作の完了後にファイルを閉じることが不可欠です。 通常、デフォルトでは、プロセスごとに3つの記述子が開かれ、それぞれファイル記述子0、1、2を持つ入力(標準入力-stdin)、出力(標準出力-stdout)、エラー(標準エラー-stderr)に使用されます。

このシステムコールは、read/write/seek(lseek)のさらなるファイル操作に使用されるファイル記述子を返します。 通常、ファイル記述子は3から始まり、開いているファイルの数に応じて1つ増えます。

オープンシステムコールに渡される引数は、パス名(相対パスまたは絶対パス)、ファイルを開く目的を示すフラグ(読み取り用に開く、O_RDONLY、書き込むため、O_WRONLY、読み取りおよび書き込み用、O_RDWR、既存のファイルに追加するため) O_APPEND、O_CREATなどで存在しない場合はファイルを作成するなど)およびユーザーまたは所有者/グループ/その他の読み取り/書き込み/実行の許可を提供する必要なモード。 モードはシンボルで言及できます。

読み取り– 4、書き込み– 2、実行– 1。

例:8進値(0で始まる)、0764は所有者に読み取り、書き込み、および実行の許可があり、グループには読み取りおよび書き込みの許可があり、その他には読み取りの許可があることを意味します。 これは、S_IRWXU |として表すこともできます。 S_IRGRP | S_IWGRP | S_IROTH。これは0700 | 0040 | 0020 | 0004→0764を意味するか、操作します。

このシステムコールは、成功すると、新しいファイル記述子IDを返し、エラーの場合は-1を返します。 エラーの原因は、errno変数またはperror()関数で特定できます。

#include<unistd.h>

int close(int fd)

上記のシステムコールは、すでに開いているファイル記述子を閉じます。 これは、ファイルが使用されなくなり、関連するリソースが他のプロセスで再利用できることを意味します。 このシステムコールは成功すると0を返し、エラーの場合は-1を返します。 エラーの原因は、errno変数またはperror()関数で特定できます。

#include<unistd.h>

ssize_t read(int fd, void *buf, size_t count)

上記のシステムコールは、ファイル記述子fdの引数、割り当てられたメモリ(静的または動的)を備えた適切なバッファ、およびバッファのサイズを使用して、指定されたファイルから読み取ります。

ファイル記述子IDは、それぞれのファイルを識別するためのもので、open()またはpipe()システムコールを呼び出した後に返されます。 ファイルを読み取る前に、ファイルを開く必要があります。 pipe()システムコールを呼び出す場合に自動的に開きます。

この呼び出しは、成功した場合に読み込まれたバイト数(ファイルの終わりに到達した場合はゼロ)を返し、失敗した場合は-1を返します。 データが利用できない場合やファイルが閉じられる場合に備えて、戻りバイトは要求されたバイト数より小さくすることができます。 障害が発生した場合に適切なエラー番号が設定されます。

失敗の原因を知るには、errno変数またはperror()関数で確認してください。

#include<unistd.h>

ssize_t write(int fd, void *buf, size_t count)

上記のシステムコールは、ファイル記述子fdの引数、割り当てられたメモリ(静的または動的)およびバッファのサイズを備えた適切なバッファを使用して、指定されたファイルに書き込みます。

ファイル記述子IDは、それぞれのファイルを識別するためのもので、open()またはpipe()システムコールを呼び出した後に返されます。

ファイルに書き込む前に、ファイルを開く必要があります。 pipe()システムコールを呼び出す場合に自動的に開きます。

この呼び出しは、成功した場合に書き込まれたバイト数(または何も書き込まれていない場合はゼロ)を返し、失敗した場合は-1を返します。 障害が発生した場合に適切なエラー番号が設定されます。

失敗の原因を知るには、errno変数またはperror()関数で確認してください。

サンプルプログラム

以下にいくつかのプログラム例を示します。

  • プログラム例1 *-パイプを使用して2つのメッセージを読み書きするプログラム。

アルゴリズム

  • ステップ1 *-パイプを作成します。
  • ステップ2 *-パイプにメッセージを送信します。
  • ステップ3 *-パイプからメッセージを取得し、標準出力に書き込みます。
  • ステップ4 *-パイプに別のメッセージを送信します。
  • ステップ5 *-パイプからメッセージを取得し、標準出力に書き込みます。

注意-すべてのメッセージを送信した後、メッセージを取得することもできます。

  • ソースコード:simplepipe.c *
#include<stdio.h>
#include<unistd.h>

int main() {
   int pipefds[2];
   int returnstatus;
   char writemessages[2][20]={"Hi", "Hello"};
   char readmessage[20];
   returnstatus = pipe(pipefds);

   if (returnstatus == -1) {
      printf("Unable to create pipe\n");
      return 1;
   }

   printf("Writing to pipe - Message 1 is %s\n", writemessages[0]);
   write(pipefds[1], writemessages[0], sizeof(writemessages[0]));
   read(pipefds[0], readmessage, sizeof(readmessage));
   printf("Reading from pipe – Message 1 is %s\n", readmessage);
   printf("Writing to pipe - Message 2 is %s\n", writemessages[0]);
   write(pipefds[1], writemessages[1], sizeof(writemessages[0]));
   read(pipefds[0], readmessage, sizeof(readmessage));
   printf("Reading from pipe – Message 2 is %s\n", readmessage);
   return 0;
}

-理想的には、システムコールごとに戻りステータスを確認する必要があります。 プロセスを簡素化するために、すべての呼び出しに対してチェックが行われるわけではありません。

実行手順

編集

gcc -o simplepipe simplepipe.c

実行/出力

Writing to pipe - Message 1 is Hi
Reading from pipe – Message 1 is Hi
Writing to pipe - Message 2 is Hi
Reading from pipe – Message 2 is Hell
  • プログラム例2 *-親プロセスと子プロセスを使用して、パイプを介して2つのメッセージを読み書きするプログラム。

アルゴリズム

  • ステップ1 *-パイプを作成します。
  • ステップ2 *-子プロセスを作成します。
  • ステップ3 *-親プロセスはパイプに書き込みます。
  • ステップ4 *-子プロセスはパイプからメッセージを取得し、標準出力に書き込みます。
  • ステップ5 *-ステップ3とステップ4をもう一度繰り返します。
  • ソースコード:pipewithprocesses.c *
#include<stdio.h>
#include<unistd.h>

int main() {
   int pipefds[2];
   int returnstatus;
   int pid;
   char writemessages[2][20]={"Hi", "Hello"};
   char readmessage[20];
   returnstatus = pipe(pipefds);
   if (returnstatus == -1) {
      printf("Unable to create pipe\n");
      return 1;
   }
   pid = fork();

  //Child process
   if (pid == 0) {
      read(pipefds[0], readmessage, sizeof(readmessage));
      printf("Child Process - Reading from pipe – Message 1 is %s\n", readmessage);
      read(pipefds[0], readmessage, sizeof(readmessage));
      printf("Child Process - Reading from pipe – Message 2 is %s\n", readmessage);
   } else {//Parent process
      printf("Parent Process - Writing to pipe - Message 1 is %s\n", writemessages[0]);
      write(pipefds[1], writemessages[0], sizeof(writemessages[0]));
      printf("Parent Process - Writing to pipe - Message 2 is %s\n", writemessages[1]);
      write(pipefds[1], writemessages[1], sizeof(writemessages[1]));
   }
   return 0;
}

実行手順

コンピレーション

gcc pipewithprocesses.c –o pipewithprocesses

実行

Parent Process - Writing to pipe - Message 1 is Hi
Parent Process - Writing to pipe - Message 2 is Hello
Child Process - Reading from pipe – Message 1 is Hi
Child Process - Reading from pipe – Message 2 is Hello

パイプを使用した双方向通信

パイプ通信は一方向の通信、つまり、親プロセスが書き込み、子プロセスが読み取り、またはその逆であると見なされますが、両方ではありません。 ただし、親と子の両方がパイプの書き込みと読み取りを同時に行う必要がある場合、解決策はパイプを使用した双方向通信です。 双方向通信を確立するには、2本のパイプが必要です。

以下は、双方向通信を達成するための手順です-

  • ステップ1 *-2つのパイプを作成します。 1つ目は、たとえばpipe1のように、親が書き込み、子が読み取ることです。 2つ目は、たとえばpipe2として、子が書き込み、親が読み取ることです。
  • ステップ2 *-子プロセスを作成します。
  • ステップ3 *-各通信に必要なのは1つのエンドポイントだけなので、不要なエンドポイントを閉じます。
  • ステップ4 *-親プロセスの不要な終了を閉じ、pipe1の終了を読み取り、pipe2の終了を書き込みます。
  • ステップ5 *-子プロセスの不要な終了を閉じ、pipe1の終了を書き込み、pipe2の終了を読み取ります。
  • ステップ6 *-必要に応じて通信を実行します。

2つのパイプ

サンプルプログラム

  • サンプルプログラム1 *-パイプを使用した双方向通信の実現。

アルゴリズム

  • ステップ1 *-書き込む親プロセスと読み取る子プロセスのpipe1を作成します。
  • ステップ2 *-子プロセスが書き込み、親プロセスが読み取り用のpipe2を作成します。
  • ステップ3 *-親側と子側からパイプの不要な端を閉じます。
  • ステップ4 *-メッセージを書き込む親プロセスと、読み取りおよび画面に表示する子プロセス。
  • ステップ5 *-メッセージを書き込むための子プロセスと、読み取りおよび画面に表示するための親プロセス。
  • ソースコード:twowayspipe.c *
#include<stdio.h>
#include<unistd.h>

int main() {
   int pipefds1[2], pipefds2[2];
   int returnstatus1, returnstatus2;
   int pid;
   char pipe1writemessage[20] = "Hi";
   char pipe2writemessage[20] = "Hello";
   char readmessage[20];
   returnstatus1 = pipe(pipefds1);

   if (returnstatus1 == -1) {
      printf("Unable to create pipe 1 \n");
      return 1;
   }
   returnstatus2 = pipe(pipefds2);

   if (returnstatus2 == -1) {
      printf("Unable to create pipe 2 \n");
      return 1;
   }
   pid = fork();

   if (pid != 0)//Parent process {
      close(pipefds1[0]);//Close the unwanted pipe1 read side
      close(pipefds2[1]);//Close the unwanted pipe2 write side
      printf("In Parent: Writing to pipe 1 – Message is %s\n", pipe1writemessage);
      write(pipefds1[1], pipe1writemessage, sizeof(pipe1writemessage));
      read(pipefds2[0], readmessage, sizeof(readmessage));
      printf("In Parent: Reading from pipe 2 – Message is %s\n", readmessage);
   } else {//child process
      close(pipefds1[1]);//Close the unwanted pipe1 write side
      close(pipefds2[0]);//Close the unwanted pipe2 read side
      read(pipefds1[0], readmessage, sizeof(readmessage));
      printf("In Child: Reading from pipe 1 – Message is %s\n", readmessage);
      printf("In Child: Writing to pipe 2 – Message is %s\n", pipe2writemessage);
      write(pipefds2[1], pipe2writemessage, sizeof(pipe2writemessage));
   }
   return 0;
}

実行手順

編集

gcc twowayspipe.c –o twowayspipe

実行

In Parent: Writing to pipe 1 – Message is Hi
In Child: Reading from pipe 1 – Message is Hi
In Child: Writing to pipe 2 – Message is Hello
In Parent: Reading from pipe 2 – Message is Hello