システム・プログラム
電子・情報工学系
新城 靖
<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 %
----------------------------------------------------------------------