
- 作者: 塚越一雄
- 出版社/メーカー: 技術評論社
- 発売日: 2000/06
- メディア: 単行本
- 購入: 3人 クリック: 56回
- この商品を含むブログ (35件) を見る
前回はこちら
今回は親子に限定したプロセス間通信についてまとめます。まずは実際に親子間でパイプ経由でデータをやり取りするテストプログラムを作成します。
1 #include <unistd.h> 2 #include <stdio.h> 3 #include <sys/types.h> 4 5 int main() 6 { 7 char buff[BUFSIZ]; 8 int ppp[2]; 9 /********************************************************************* 10 * ppp - 親プロセスへデータを受け渡すpipe用ファイルディスクリプタ配列 11 * 12 * ppp[0] file discriptor for reading 13 * ppp[1] file discriptor for writing 14 *********************************************************************/ 15 16 int ppc[2]; 17 /********************************************************************* 18 * ppc - 子プロセスへデータを受け渡すpipe用ファイルディスクリプタ配列 19 * 20 * ppc[0] file discriptor for reading 21 * ppc[1] file discriptor for writing 22 *********************************************************************/ 23 24 pid_t pid; 25 26 char *msg_p_to_c = "parent to child"; 27 char *msg_c_to_p = "child to parent"; 28 29 /* pipeを開く */ 30 if (pipe(ppp) == -1 || pipe(ppc) == -1) 31 { 32 perror("pipe()"); 33 return 1; 34 } 35 36 /* 子プロセス作成 */ 37 if ((pid = fork()) == -1) 38 { 39 perror("fork()"); 40 return 2; 41 } 42 43 /* 親プロセスはここから */ 44 else if ( pid > 0 ) 45 { 46 // 親プロセス→子プロセス パイプへのデータ書き込み // 47 if (write(ppc[1], msg_p_to_c, strlen(msg_p_to_c) + 1) == -1 ) 48 { 49 perror("write() from parent to child"); 50 close(ppc[1]); 51 close(ppp[0]); 52 return 1001; 53 } 54 55 // 子プロセス→親プロセス パイプからデータ読み込み // 56 if (read(ppp[0], buff, BUFSIZ) == -1 ) 57 { 58 perror("read() from pipe"); 59 close(ppc[1]); 60 close(ppp[0]); 61 return 1002; 62 } 63 printf("i am parent process : [receive message] %s\n", buff); 64 close(ppc[1]); 65 close(ppp[0]); 66 } 67 68 /* 子プロセスはここから */ 69 else 70 { 71 // 子プロセス→親プロセス パイプへのデータ書き込み // 72 if (write(ppp[1], msg_c_to_p, strlen(msg_c_to_p) + 1) == -1 ) 73 { 74 perror("write() from child to parent"); 75 close(ppc[0]); 76 close(ppp[1]); 77 return 2001; 78 } 79 80 // 親プロセス→子プロセス パイプからデータ読み込み // 81 if (read(ppc[0], buff, BUFSIZ) == -1 ) 82 { 83 perror("read() from pipe"); 84 close(ppc[0]); 85 close(ppp[1]); 86 return 2002; 87 } 88 printf("i am child process : [receive message] %s\n", buff); 89 close(ppc[0]); 90 close(ppp[1]); 91 } 92 93 return 0; 94 }
2点、本が誤っている箇所があるので追記。
(1) 親と子で処理が分かれたところで使用しないパイプを閉じていましたが閉じちゃダメ
→ ファイルディスクリプタは共有なので一方を閉じると使えなくなる(2) sys/types.hもincludeする
→ pid_tが定義されている
で、これを実行してみます
[itotto@itotto ]$ gcc -o fam_pipe fam_pipe.c [itotto@itotto ]$ ./fam_pipe i am parent process : [receive message] child to parent i am child process : [receive message] parent to child [itotto@itotto ]$
互いに送信したメッセージを受信している事が分かります。パイプを2つ開いて互いに書き込んで互いに読み込んでいるわけですから、当然です。
さて。ここまでは大丈夫なのですが、例えばfork()で作成した子プロセスがexec()した場合を考えて見ます。単にfork()しただけであれば、fork()前に開いておいたpipeのファイルディスクリプタが利用できますが、一旦exec()してしまうと全くの別プロセスになってしまうのでこれを利用する事が出来なくなってしまいます。
この本では
を紹介しています。前者の「引数でディスクリプタを渡す方法」は全然面白くないので、ここでは後者を説明します。
1 #include <unistd.h> 2 #include <stdio.h> 3 #include <sys/types.h> 4 5 int main() 6 { 7 int pipe_fd[2]; 8 pid_t pid ; 9 10 /* pipeを開く */ 11 if (pipe(pipe_fd) == -1) 12 { 13 perror("pipe"); 14 return 1; 15 } 16 17 /* 自プロセスを子プロセスに複写 */ 18 if ((pid = fork()) == -1) 19 { 20 perror("fork()"); 21 return 2; 22 } 23 24 /* 以下親プロセス専用の処理 */ 25 else if ( pid > 0 ) 26 { 27 // 標準入力を閉じる // 28 close(fileno(stdin)); 29 30 // 標準入力にパイプをリダイレクト // 31 dup(pipe_fd[0]); 32 close(pipe_fd[0]); 33 34 close(pipe_fd[1]); 35 36 if (execlp("less", "less", "-r", NULL) == -1) 37 { 38 perror("execlp()"); 39 return 1001; 40 } 41 42 } 43 /* 親プロセス専用ここまで */ 44 45 /* 以下子プロセスのターン */ 46 else 47 { 48 // 標準出力を閉じる // 49 close(fileno(stdout)); 50 51 // 標準出力にパイプをリダイレクト // 52 dup(pipe_fd[1]); 53 close(pipe_fd[1]); 54 55 close(pipe_fd[0]); 56 57 if (execlp("ls", "ls", "--color", "-C", NULL) == -1) 58 { 59 perror("execlp()"); 60 return 2001; 61 } 62 63 } 64 /* 子プロセス専用ここまで */ 65 66 return 0; 67 }
fork()で親子それぞれの処理に分かれた後に、(1) 親プロセス側でパイプ読取用のファイルディスクリプタを標準入力へリダイレクトし、(2) 子プロセス側でパイプ書込用のファイルディスクリプタを標準出力へリダイレクトさせてます。
こうする事で書き込む方は標準出力に出力し、読み取る方は標準入力を読み取ることでファイルディスクリプタが不明のままでもプロセス間の通信をすることが可能となります。
[itotto@itotto ]$ gcc -o pipe_via_stdio pipe_via_stdio.c [itotto@itotto ]$ ./pipe_via_stdio executable pipe_via_stdio pipe_via_stdio.c source [itotto@itotto ]$
というわけで匿名パイプはここまで。想像してたのよりも簡単で分かりやすい印象です。