C の複数のパイプ

Waqar Aslam 2023年10月12日
  1. C のパイプの概要
  2. C で複数のパイプを実装する
C の複数のパイプ

この記事では、C での複数パイプの実装について説明します。

C のパイプの概要

パイプは、一方のプロセスから返された標準出力が他方のプロセスの標準入力になる、2つの異なるプロセス間のリンクの抽象表現です。 パイプは、リンクされたプロセスが相互に通信 (プロセス間通信) できるようにする UNIX オペレーティング システムの重要なコンポーネントです。

パイプは一方向にしか通信できません。 したがって、それらを使用して、あるプロセスがパイプに書き込み、別のプロセスがパイプから読み取ることができます。 パイプは、仮想ファイルと同じ方法で処理されるメイン メモリの領域であり、このアクションによって 1つが開かれます。

C で複数のパイプを実装する

1つの親プロセスと 2つの子プロセスの例を見てみましょう。 完全であることが保証された値を親プロセスから子プロセスにパイプ経由で送信し、その値を親プロセスに送り返します。

まず、ライブラリをインポートして、アプリケーションに含まれるクラスと関数にアクセスする必要があります。 さらに、main() 関数を開発する必要があります。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

int main(int argc, char* argv[]) {}

main 関数内で、3つのパイプのファイル記述子を生成して、他のプロセスで読み書きできるようにします。 次に、i 型の変数を整数として定義して、3つのパイプを生成する for ループを確立し、すべてのパイプの値が zero より小さいことを確認して、 エラー。

int fd[3][2];
int i;
for (i = 0; i < 3; i++) {
  if (pipe(fd[i]) < 0) {
    return 1;
  }
}

パイプのオープンが完了したら、次のステップは各プロセスのフォークを開始することです。 その結果、processIdOne という変数を確立してから、fork() 関数を割り当てる必要があります。

また、チェックを適用して、processIdOne の値がゼロ以上であることを確認します。

int processIdOne = fork();
if (processIdOne < 0) {
  return 2;
}

ここで、processIdOne の値がゼロに等しいかどうかを確認します。 そうであれば、これは最初の子プロセスにいることを示しています。 close() 関数を最初の子プロセス内で使用して、このプロセスに属するものを除くすべてのファイル記述子を閉じる必要があります。

x という名前の整数変数を作成し、データ型を int にします。 ここで、read() メソッドを使用して、ファイル記述子 &x と値を読み取るサイズを指定し、その値が zero より小さいかどうかをチェックしてから、エラー メッセージを表示します。 は。

次に、fileDescriptor[1][1] の値が 0 未満かどうかを確認し、0 未満の場合はエラーを表示します。 write() メソッドを利用し、そのパラメーターを渡し、fileDescriptor[1][1] を使用して書き込みます。

最初の子プロセスのファイル記述子は、最後の手順で閉じる必要があります。

if (processIdOne == 0) {
  // Child process 1
  close(fileDescriptor[0][1]);
  close(fileDescriptor[1][0]);
  close(fileDescriptor[2][0]);
  close(fileDescriptor[2][1]);
  int x;
  if (read(fileDescriptor[0][0], &x, sizeof(int)) < 0) {
    return 3;
  }
  x += 10;
  if (write(fileDescriptor[1][1], &x, sizeof(int)) < 0) {
    return 4;
  }
  close(fileDescriptor[0][0]);
  close(fileDescriptor[1][1]);
  return 0;
}

次のステップでは、processIdTwo という変数を設定し、fork() 関数を割り当てます。 さらに、processIdTwo の値がゼロ以下でないことを確認するためのチェックを実行する必要があります。

int processIdTwo = fork();
if (processIdTwo < 0) {
  return 5;
}

ここで、processIdTwo の値がゼロかどうかを確認します。 存在する場合は、2 番目の子プロセスにいることを示します。 2 番目の子プロセス内では、この特定のプロセスを除いて、すべてのファイル記述子が close() メソッドを使用して閉じられていることを確認する必要があります。

x. というデータ型 int の変数を宣言します。 ここで、read() メソッドを使用して、ファイル記述子 &x と値を読み取るサイズを入力し、値が 0 未満の場合にエラーが表示されるようにします。

次に、値 10 を追加して x の値を増やし、fileDescriptor[2][1] を使用して書き込みを行うパラメーターを指定した write() 関数を使用します。 次に、その値が 0 より小さいかどうかを確認し、0 より小さい場合はエラー メッセージを表示します。

最後に、2 番目の子プロセスのファイル記述子を閉じます。

if (processIdTwo == 0) {
  close(fileDescriptor[0][0]);
  close(fileDescriptor[0][1]);
  close(fileDescriptor[1][1]);
  close(fileDescriptor[2][0]);
  int x;
  if (read(fileDescriptor[1][0], &x, sizeof(int)) < 0) {
    return 6;
  }
  x += 10;
  if (write(fileDescriptor[2][1], &x, sizeof(int)) < 0) {
    return 7;
  }
  close(fileDescriptor[1][0]);
  close(fileDescriptor[2][1]);
  return 0;
}

前に行ったように、このプロセスに対応するものを除いて、親プロセス内の他のすべてのファイル記述子を閉じます。

変数 x を整数型として宣言します。 ここで、read() 関数を使用して、ファイル記述子 &x と値を読み取るサイズを指定し、その値がゼロより小さいかどうかをチェックして、エラーを表示するかどうかを決定します。

次に、値 10 を追加して x の値を増やします。 fileDescriptor[2][0] を使用して書き込みを行うパラメーターを指定した write() 関数を使用し、その値が 0 未満かどうかをチェックして、エラー メッセージを表示するかどうかを決定します。

開いているファイル記述子を閉じて停止します。

processIdOneprocessIdTwo の両方に対して、waitpid() メソッドを使用する必要があります。 この関数は、すべてのプロセスが完了するのを待ってから、次の操作に進みます。

close(fileDescriptor[0][0]);
close(fileDescriptor[1][0]);
close(fileDescriptor[1][1]);
close(fileDescriptor[2][1]);
int x = 0;
if (write(fileDescriptor[0][1], &x, sizeof(int)) < 0) {
  return 8;
}
if (read(fileDescriptor[2][0], &x, sizeof(int)) < 0) {
  return 9;
}
printf("The value received from the child processes is: %d\n", x);
close(fileDescriptor[0][1]);
close(fileDescriptor[2][0]);

waitpid(processIdOne, NULL, 0);
waitpid(processIdTwo, NULL, 0);

C で複数のパイプを実装する完全なソース コード:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

int main(int argc, char* argv[]) {
  int fileDescriptor[3][2];
  int i;
  for (i = 0; i < 3; i++) {
    if (pipe(fileDescriptor[i]) < 0) {
      return 1;
    }
  }

  int processIdOne = fork();
  if (processIdOne < 0) {
    return 2;
  }

  if (processIdOne == 0) {
    // Child process 1
    close(fileDescriptor[0][1]);
    close(fileDescriptor[1][0]);
    close(fileDescriptor[2][0]);
    close(fileDescriptor[2][1]);
    int x;
    if (read(fileDescriptor[0][0], &x, sizeof(int)) < 0) {
      return 3;
    }
    x += 10;
    if (write(fileDescriptor[1][1], &x, sizeof(int)) < 0) {
      return 4;
    }
    close(fileDescriptor[0][0]);
    close(fileDescriptor[1][1]);
    return 0;
  }

  int processIdTwo = fork();
  if (processIdTwo < 0) {
    return 5;
  }

  if (processIdTwo == 0) {
    // Child process 2
    close(fileDescriptor[0][0]);
    close(fileDescriptor[0][1]);
    close(fileDescriptor[1][1]);
    close(fileDescriptor[2][0]);
    int x;
    if (read(fileDescriptor[1][0], &x, sizeof(int)) < 0) {
      return 6;
    }
    x += 10;
    if (write(fileDescriptor[2][1], &x, sizeof(int)) < 0) {
      return 7;
    }
    close(fileDescriptor[1][0]);
    close(fileDescriptor[2][1]);
    return 0;
  }

  // Parent process
  close(fileDescriptor[0][0]);
  close(fileDescriptor[1][0]);
  close(fileDescriptor[1][1]);
  close(fileDescriptor[2][1]);
  int x = 0;
  if (write(fileDescriptor[0][1], &x, sizeof(int)) < 0) {
    return 8;
  }
  if (read(fileDescriptor[2][0], &x, sizeof(int)) < 0) {
    return 9;
  }
  printf("The value received from the child processes is: %d\n", x);
  close(fileDescriptor[0][1]);
  close(fileDescriptor[2][0]);

  waitpid(processIdOne, NULL, 0);
  waitpid(processIdTwo, NULL, 0);

  return 0;
}

出力:

The value received from the child processes is: 20
著者: Waqar Aslam
Waqar Aslam avatar Waqar Aslam avatar

I am Waqar having 5+ years of software engineering experience. I have been in the industry as a javascript web and mobile developer for 3 years working with multiple frameworks such as nodejs, react js, react native, Ionic, and angular js. After which I Switched to flutter mobile development. I have 2 years of experience building android and ios apps with flutter. For the backend, I have experience with rest APIs, Aws, and firebase. I have also written articles related to problem-solving and best practices in C, C++, Javascript, C#, and power shell.

LinkedIn

関連記事 - C Pipe