pipe() と dup()

システム・プログラム

                                       電子・情報工学系
                                       新城 靖
                                       <yas@is.tsukuba.ac.jp>

このページは、次の URL にあります。
http://www.hlla.is.tsukuba.ac.jp/~yas/coins/syspro-2000/2000-05-01 /process-pipe.html
あるいは、次のページから手繰っていくこともできます。
http://www.hlla.is.tsukuba.ac.jp/~yas/coins/
http://www.is.tsukuba.ac.jp/~yas/index-j.html

■pipe() と dup()

シェルで、次のようなプログラムを動かすこと考える。

----------------------------------------------------------------------
% echo "hello,world" | tr a-z A-Z [←]
HELLO,WORLD
% []
----------------------------------------------------------------------

この例では、echo のプロセスと、tr のプロセスは、パイプで接続されている。 パイプは、open() したファイルと同じようにread() したり write() したり することがでる。しかし実際には、ファイルではなく、プロセスとプロセスが データを交換する仕組(プロセス間通信の仕組)の1つである。

パイプを作るには、pipe() システム・コールを使う。これで、パイプ が1本作られ、2つのファイル記述子(読込み用と書込み用)が返される。

pipe() システム・コールで作られたファイル記述子は、しばしば dup() シス テム・コールで、0, 1 に変えられる。dup() システム・コールは、記述子を コピーするものである。小さい数字から探していくので、たとえば close(0) の直後に dup(fd) すると、fd が 0 にコピーされる。

dup() よりも、dup2() の方が便利である。


----------------------------------------------------------------------
   1:	/*
   2:	        pipe-rw.c -- pipe() と dup() を使ったプログラム
   3:	        ~yas/syspro1/ipc/pipe-rw.c
   4:	        $Header: /home/lab2/OS/yas/syspro1/ipc/RCS/pipe-rw.c,v 1.5 1998/05/25 15:34:59 yas Exp $
   5:	        Start: 1997/05/26 20:43:29
   6:	*/
   7:	
   8:	#include <stdio.h>
   9:	#include <unistd.h>
  10:	
  11:	extern  void parent( int fildes[2] );
  12:	extern  void child( int fildes[2] );
  13:	
  14:	main()
  15:	{
  16:	    int fildes[2] ;
  17:	    pid_t pid ;
  18:	
  19:	        if( pipe(fildes) == -1)
  20:	        {
  21:	            perror("pipe");
  22:	            exit( 1 );
  23:	        }
  24:	        /* fildes[0] -- 読み込み用
  25:	         * fildes[1] -- 書き込み用
  26:	         */
  27:	        if( (pid=fork()) == 0 )
  28:	        {
  29:	            child( fildes );
  30:	        }
  31:	        else if( pid > 0 )
  32:	        {
  33:	            parent( fildes );
  34:	        }
  35:	        else
  36:	        {
  37:	            perror("fork");
  38:	            exit( 1 );
  39:	        }
  40:	}
  41:	
  42:	void parent( int fildes[2] )
  43:	{
  44:	    char *p ;
  45:	        close( fildes[0] );
  46:	        close( 1 );
  47:	        dup( fildes[1] );
  48:	        close( fildes[1] );
  49:	
  50:	        p = "hello,world\n" ;
  51:	        while( *p )
  52:	        {
  53:	            write( 1,p++,1 );
  54:	        }
  55:	}
  56:	
  57:	void child( int fildes[2] )
  58:	{
  59:	    char c ;
  60:	        close( fildes[1] );
  61:	        close( 0 );
  62:	        dup( fildes[0] );
  63:	        close( fildes[0] );
  64:	
  65:	        while( read(0,&c,1) >0 )
  66:	        {
  67:	            putchar( toupper(c) );
  68:	        }
  69:	}
----------------------------------------------------------------------

実行例。

----------------------------------------------------------------------
% ./pipe-rw [←]
HELLO,WORLD
%
----------------------------------------------------------------------

■練習問題

★練習問題40 3個のプロセスをパイプで結ぶ

3個のプロセスの標準入出力を、2つのパイプで結びなさい。

ヒント:使わないパイプのファイル記述子は、全部 close() すること。パイ プの書き込み側のファイル記述子が開いている間は、read() しても EOF (End Of File) にならない。

先にパイプを2つ作ってから2回 fork() してもよい。パイプを1つ作って fork() してから もう1つパイプを作って fork() するという方法でもよい。

★練習問題41 書き手がいないパイプ

書き手(write()するプロセス)がいないパイプから読み出そうとすると、どう なるか確かめなさい。

ヒント:書き手がいないパイプは、全ての書込み側のファイル記述子を closeすると作れる。

★練習問題42 読み手がいないパイプ

読み手がいないパイプに書き込むとどうなるか確かめなさい。

★練習問題43 パイプ用のバッファの大きさ

各パイプには、オペレーティング・システムのカーネルの中にバッファが割り 当てられてている。この大きさを調べるプログラムを作りなさい。

ヒント:プロセスを fork() しなくても、パイプに書くことはできる。プロセ スが1個の状態で、バッファの大きさ以上のデータを書き込むと、プロセスが ブロックされる(先に進まなくなる)。

★練習問題44 読み手が複数いるパイプ

1つのパイプに読み手(read() するプロセス)が複数いた場合、どうなるか。 逆に、書き手が複数いた場合、どうなるか。

★練習問題45 popen() ライブラリ関数

プロセスを実行してその結果を得るには、popen() ライブラリ関数が便利であ る。
----------------------------------------------------------------------
     FILE *popen(const char *command, const char *type);
     int pclose (FILE *stream);
----------------------------------------------------------------------
これを利用して、プロセスを作成し、プロセスにデータを与えたり、あるいは、 プロセスからデータを受け取るプログラムをつくりなさい。

たとえば、expr コマンドを実行して、その結果を受け取るプログラムをつく りなさい。expr は、次のように引数で与えられた式を評価し、結果を標準出 力に返すものである。


----------------------------------------------------------------------
% expr 1 + 2 [←]
3
% []
----------------------------------------------------------------------

この課題では、expr コマンドに似たようなプログラム作るのではなく、それ をそのまま利用して、結果を受け取るプログラムを作る。実行するプログラム としては、expr 以外に次のようなものが考えられる。
↑[もどる] ←[4月24日] ・[5月01日] →[5月08日] [課題]
Last updated: 2000/04/30 20:43:18
Yasushi Shinjo / <yas@is.tsukuba.ac.jp>