<目次>
(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に処理依頼する際に引き渡します。