システム・プログラム 電子・情報工学系 新城 靖 <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
この例では、echo のプロセスと、tr のプロセスは、パイプで接続されている。 パイプは、open() したファイルと同じようにread() したり write() したり することがでる。しかし実際には、ファイルではなく、プロセスとプロセスが データを交換する仕組(プロセス間通信の仕組)の1つである。---------------------------------------------------------------------- % echo "hello,world" | tr a-z A-ZHELLO,WORLD %
----------------------------------------------------------------------
パイプを作るには、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-rwHELLO,WORLD % ----------------------------------------------------------------------
ヒント:使わないパイプのファイル記述子は、全部 close() すること。パイ プの書き込み側のファイル記述子が開いている間は、read() しても EOF (End Of File) にならない。
先にパイプを2つ作ってから2回 fork() してもよい。パイプを1つ作って fork() してから もう1つパイプを作って fork() するという方法でもよい。
ヒント:書き手がいないパイプは、全ての書込み側のファイル記述子を closeすると作れる。
ヒント:プロセスを fork() しなくても、パイプに書くことはできる。プロセ スが1個の状態で、バッファの大きさ以上のデータを書き込むと、プロセスが ブロックされる(先に進まなくなる)。
---------------------------------------------------------------------- FILE *popen(const char *command, const char *type); int pclose (FILE *stream); ----------------------------------------------------------------------これを利用して、プロセスを作成し、プロセスにデータを与えたり、あるいは、 プロセスからデータを受け取るプログラムをつくりなさい。
たとえば、expr コマンドを実行して、その結果を受け取るプログラムをつく りなさい。expr は、次のように引数で与えられた式を評価し、結果を標準出 力に返すものである。
この課題では、expr コマンドに似たようなプログラム作るのではなく、それ をそのまま利用して、結果を受け取るプログラムを作る。実行するプログラム としては、expr 以外に次のようなものが考えられる。---------------------------------------------------------------------- % expr 1 + 23 %
----------------------------------------------------------------------