トップ «前の日記(2006-11-07 [火]) 最新 次の日記(2006-11-09 [木])» 編集

SewiGの日記

2004|01|04|05|06|07|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|

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);
	}
}

Copyright © 2004-2008 SewiG All rights reserved.