SewiGの日記
2006-11-08 [水] [長年日記]
■ [Programming] UNIXでパイプ作ってプロセス間通信
あまりにも頻繁に来る質問なので、解説してみる。
pipe()というシステムコールを使えば、パイプが作られて、そのパイプの入力と出力となるファイル記述子が返されます。あとは、このパイプを他のプロセスと共有してやれば通信ができます。
ここでは、forkで子プロセスを作って、親子間で通信してみましょう。fork()というシステムコールで、自分自身のプロセスのコピーができます。このままではまったく同じ動作をするプロセスが増えるだけなので、fork()のあとに実行中のプロセスが親プロセスなのか子プロセスなのかを判定してやれば2通りの動作を並行して動作させることができますよね。これはforkしたときの戻り値で判別できます。0なら子、0より大きければ親。
このままでは、パイプは自分自身のプロセスにしか接続されていないので、子→親とデータを受け渡す場合には次のようにします。つまり子の出力をパイプの入力につないで、親の入力をパイプの出力につなぎます。
子:標準出力はいらないのでclose(1)、dup(fds[1])で今closeした場所にパイプのwriteをコピー
親:標準入力はいらないのでclose(0)、dup(fds[0])で今closeした場所にパイプのreadをコピー
それ以外のcloseはお行儀よく不要な入出力を閉じています。
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
int main() {
int fds[2];
pid_t pid;
int status;
char c;
// fds[0] read, fds[1] write
if (pipe(fds) == -1) {
perror("pipe");
exit(-1);
}
if ((pid = fork()) < 0) {
perror("fork");
exit(1);
} else if (pid == 0) {
// Child process
close(fds[0]);
close(1);
dup(fds[1]);
close(fds[1]);
write(1, "hello", sizeof("hello"));
close(1);
} else {
// Parent process
close(fds[1]);
close(0);
dup(fds[0]);
close(fds[0]);
wait(&status);
while (read(0, &c, 1) > 0) {
write(1, &c, 1);
}
write(1, " world\n", sizeof(" world\n"));
close(0);
}
}