Transcript fd[0]
パイプライン通信 パイプライン通信 標準入出力とパイプライン シェルとパイプライン パイプによるプロセス間通信の仕組み pipeシステム・コール pipeシステム・コールとプロセス間通信 pipeシステム・コールと、ファイル識別子 パイプread/writeプログラミング パイプライン通信プログラミング コマンドパイプライン型通信プログラミング dupシス テム・コール dupシス テム・コールと、ファイル識別子 パイプdupeプログラミング パイプライン通信 標準入出力とパイプライン cmd < file fileをcmdの標準入力にする 標準入力 キーボード ファイル cmd > file cmdの標準出力をfileにする 標準出力 ディスプレイ ファイル |: パイプライン (前のコマンドの標準出力を 後のコマンドの標準入力に する) $ cat > input ooki oida okajima $ tr o i < input iiki iida ikajima $ tr o i < input > output $ cat output iiki iida ikajima $ tr o i < input | sort > output $ cat output iida iiki ikajima $ パイプライン通信 シェルとパイプライン シェルで、次のようなプログラムを動 かすこと考える。 echo tr % echo "hello,world" | tr '[a-z]' '[A-Z]' HELLO,WORLD % write() | この例では、echo のプロセスと、tr の プロセスは、パイプで接続されている。 パイプは、open() したファイルと同じよ うにread() したり write() したり するこ とがでる。 しかし実際には、ファイルではなく、プ ロセスとプロセスが データを交換する 仕組(プロセス間通信の仕組)の1つ である。 片方のプロセ スが write() したデータ を、もう片方のプロセスがread() でき る。 read() パイプライン通信 パイプによるプロセス間通信の仕組み パイプにより提供されるプロセス間通信 のサービスは、 (単方向の)ストリームと も呼ばれる。 FIFO (First In, First Out)や Queue (待ち 行列) と呼ばれることもある。 echo write() | tr read() パイプは、内部的には、8k バイト程度の バッファ(メモリ)がオペレーティング・シス テ ムのカーネルにある。 バッファが一杯になると、書込み側 のプロセスは write() で止まる (write() システムコールの呼び出し が元にもどらない。) バッファが空だと、read() で止まる。 全部の書込み側の口が close() され ると、read() で EOF が返る。 FIFO (First In, First Out) Queue パイプライン通信 pipeシステム・コール パイプを作るには、pipe() システ ム・コールを使う。 1つのパイプに対して、2つの ファイル記述子(読込み用と書込 み用)が返される。 インクルードファイル #include <unistd.h> 書式 int pipe(int filedes[2]); 戻値 成功時 0 失敗時 -1 使用例 int fd[2]; pipe(fd); プロセス fd[0] pipe(fd); fd[0] =3 read用 fd[1] =4 fd[1] write用 パイプ バッファ パイプライン通信 pipeシステム・コールと、プロセス間通信 プロセスA pipe(fd); fd[0] プロセスB read用 write用 read用 pipe(fd); fd[1] fd[0] パイプバッファ write用 fd[1] パイプライン通信 pipeシステム・コールと、ファイル識別子(1/3) パイプライン通信 pipeシステム・コールと、ファイル識別子(2/3) パイプライン通信 pipeシステム・コールと、ファイル識別子(3/3) パイプライン通信 パイプread/write (1/2) プロセス fd[0] pipe(fd); fd[0] =3 read用 fd[1] =4 fd[1] write用 パイプ バッファ パイプライン通信 パイプread/write (2/2) pipe-self.c パイプライン通信 パイプライン通信 (1/2) プロセスA プロセスB read用 pipe(fd); write用 fd[0] read用 pipe(fd); fd[1] fd[0] パイプバッファ write用 fd[1] パイプライン通信 パイプライン通信 (2/2) pipe-processes.c 親プロセスは、パイプの読込み側(fildes[0])を閉じる。 そ して、文字列から1バイトずつ取り出し、0 が現れるまで、 パイプの書込み側(fildes[1])に書込む。 子プロセスは、パイプの書込み側(fildes[1])を閉じる。 そ してパイプの読込み側(fildes[0])から1バイト取り出す。こ れをtoupper() で大文字に変換して、標準出力(1)に書き 出す。 パイプライン通信 コマンド型パイプライン通信 (1/3) プロセスA pipe(fd); fd[0] プロセスB read用 write用 read用 pipe(fd); fd[1] fd[0] パイプバッファ write用 fd[1] パイプライン通信 コマンド型パイプライン通信 (2/3) parent.c 親プロセス 1. パイプラインを生成 2. 標準入力から数字を入力 3. 子プロセスchildを生成 4. パイプラインに数字を書込む 5. 子プロセス終了後パイプラインを 読む 6. 読み出した数値を出力 パイプライン通信 コマンド型パイプライン通信 (3/3) child.c 子プロセス 1. 引数からファイルディスクリプタを得る 2. パイプラインから数字を読む 3. 数字を2乗する 4. 2乗した結果をパイプラインに書き込む $ gcc -o parent parent.c $ gcc -o child child.c $ ./parent 512 512 x 512 = 262144 $ パイプライン通信 dupeシステム・コール pipe() システム・コールで 作られたファイル記述子 は、しばしば dup() シス テム・コールで、0, 1 に変 えられる。 dup() システム・コールは、 ファイル記述子を コピー するものである。 dup() システム・コールは、 ファイル記述子を、小さ い数字から探していくの で、たとえば close(0) の 直後に dup(fd) すると、fd が 0 にコピーされる。 標準出力をパイプに 切替 close( 1 ); dup( fildes[1] ); 標準入力をパイプに 切替 close( 0 ); dup( fildes[0] ); パイプライン通信 dupeシステム・コールと、ファイル識別子 標準出力 をパイプに 切替 標準入力 をパイプに 切替 パイプライン通信 パイプdupeプログラミング pipe-dupe-processes.c