<目次>
(1) パイプ通信とは?概要やサンプルプログラムをご紹介
(1-1) パイプ通信の概要
(1-2) パイプ通信の構文
(1-3) パイプ通信のサンプルプログラム①(単一プロセス版)
(1-4) パイプ通信とは?概要やサンプルプログラムをご紹介
(1-5) 用語
(1) パイプ通信とは?概要やサンプルプログラムをご紹介
(1-1) パイプ通信の概要

●pipe()システムコールの特徴
(1-2) パイプ通信の構文
・①パイプ生成
pipe関数の引数にint型の配列(2要素)を与える事で、その配列内に読込み用(read)と書込み用(write)の2つのファイルディスクリプタを生成します。
具体的には「pipefds[0]」が読込み用で、「pipefds[1]」が書込み用です。「pipefds[1]」に書き込んだ内容を「pipefds[0]」から読み込む事ができます。
(構文)
int pipe(int pipefds[2]);
・②パイプのオープン
(構文)
int open(const char *pathname, int flags);
・③パイプの書き込み
ssize_t write(int fd, const void *buf, size_t count); //# 例:第1引数は書込み用のfds[1]を指定 write(fds[1], msg1, 32);
・④パイプの読み込み
ssize_t read(int fd, void *buf, size_t count); //# 例:第1引数は書込み用のfds[0]を指定 read(fds[0], buffer, 32);
(1-3) パイプ通信のサンプルプログラム①(単一プロセス版)
(図131)イメージ図

(サンプル)
#include <iostream>
#include <unistd.h>
#include <cstdlib>
#define MESSAGESIZE 32
char* msg1 = "Apple";
char* msg2 = "Banana";
char* msg3 = "Strawberry";
char* msg4 = "Melon";
int main()
{
char buffer[MESSAGESIZE];
int fds[2], i;
//# パイプの生成
//# エラーの場合、処理終了する
if (pipe(fds) < 0)
exit(1);
//# 正常の場合、処理継続する
//# パイプへの書込み
write(fds[1], msg1, MESSAGESIZE);
write(fds[1], msg2, MESSAGESIZE);
write(fds[1], msg3, MESSAGESIZE);
write(fds[1], msg4, MESSAGESIZE);
//# パイプからの読込み
for (i = 0; i < 4; i++) {
//# パイプの読込み
read(fds[0], buffer, MESSAGESIZE);
std::cout << buffer << std::endl;
}
return 0;
}

#コマンド g++ -g -o ./[ご自身のプログラム名] ./[ご自身のプログラム名].cpp -Wno-write-strings #例 g++ -g -o ./pipe_test ./pipe_test.cpp -Wno-write-strings


パイプ通信のサンプルプログラム②(親プロセス&子プロセス版)
次に、親プロセスと子プロセス間のパイプ通信の例です。この例では、子プロセスから書き込み(write)した情報を、親プロセスで読み込み(read)する例です。
ポイントはfork()(⇒★リンク)で親プロセスから子プロセスを起動している点です(ここが前の例との一番の違い)。パイプを生成した後にfork()で子プロセスを起動すると、親プロセスと子プロセスとの間でパイプ通信が可能になります。
(図141)

(サンプル)
#include <iostream>
#include <unistd.h>
#include <cstdlib>
#include <sys/types.h>
#include <sys/wait.h>
#define MESSAGESIZE 32
char* msg1 = "Apple";
char* msg2 = "Banana";
char* msg3 = "Strawberry";
char* msg4 = "Melon";
int main()
{
char buffer[MESSAGESIZE];
int fds[2], pid, bytelen;
//# パイプの生成(fds[0]=read用、fds[1]=write用)
//# エラーの場合、処理終了する
if (pipe(fds) < 0)
exit(1);
//# 正常の場合、処理継続する
//# ↓このif文の中は「親プロセス」による書き込み(write)処理
if ((pid = fork()) > 0) {
//# パイプへの書込み
std::cout << pid << std::endl;
write(fds[1], msg1, MESSAGESIZE);
write(fds[1], msg2, MESSAGESIZE);
write(fds[1], msg3, MESSAGESIZE);
write(fds[1], msg4, MESSAGESIZE);
// PIDを標準出力に表示
std::cout << "PID(Parent Process) : " << (long)getpid() << std::endl;
// ハング防止
close(fds[1]);
wait(NULL);
}
//# ↓このelse文の中は「子プロセス」による読み込み(read)処理
//# (子プロセスではfork()以降に記述されている処理が実行されるため)
else {
// ハング防止
close(fds[1]);
// データがある間(while)読み込みを続ける
while ((bytelen = read(fds[0], buffer, MESSAGESIZE)) > 0)
// 読み込んだ値を標準出力に表示
std::cout << buffer << std::endl;
// PIDを標準出力に表示
std::cout << "PID(Child Process) : " << (long)getpid() << std::endl;
// バイト長が0の場合(値が無い場合)
if (bytelen != 0)
exit(2);
std::cout << “### FINISH READING ###” << std::endl;
}
return 0;
}
(図142)

・コンパイル
GCCコンパイラ等で、プログラムをコンパイルします。
#コマンド g++ -g -o ./ [ご自身のプログラム名] ./[ご自身のプログラム名].cpp -Wno-write-strings #例 g++ -g -o ./pipe_test2 ./pipe_test2.cpp -Wno-write-strings
(図143)

(図144)

用語
●①ssize_t
・「size_t」は割当てされたブロックのサイズを表現するために使われる、「符号なし整数型」を表す型です。
・一方で「s」を付けた「ssize_t」は同じ用途の「符号付き整数型」バージョンです。「負の数」を返却する可能性がある場合は「ssize_t」を使用します(エラーを意味する「-1」を使用する場合など)
●ファイルディスクリプタとは
ファイルやパイプ等の操作(read/write等)をする際に、操作対象を特定するために割り当てされた一意な番号で、OSに処理依頼する際に引き渡します。