Page 22 マルチプロセス

page1からpage21までで一応C言語(gcc)の基本的な部分を書いたつもりで、このページからは少し難しいことを扱っていきます。

このページでは新しいプロセスを立ち上げる方法について書きます。

新しいプロセスを立ち上げるにはforkを使用します。unistd.hのインクルードが必要です。

pid_t fork(void)

forkの戻り値は少し複雑です。forkは新しいプロセスを起動する関数ですので、成功した場合は親プロセスと子プロセス両方に値が返されます。子プロセスには0が、親プロセスには子プロセスのプロセスID(PIDなどと略されます)が返されます。失敗した場合は-1が返ります。

forkがどのような効果を持っているのか、実際に見てみましょう。

/* プロセス起動の例 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char* argv[]){  
	sleep(60);

	fork();
  
	sleep(60);

	return 0;
}

何も出力しないプログラムです。sleepは指定秒数待機する関数で、このプログラムではforkの前後1分の待機時間を設けています。

システムモニタでプロセスを監視すると・・・(a.outが実行したプログラムです)

プログラム開始後1分間はこのような状態です。a.outが1つだけあります。1分経過後(fork()実行後)は次のようになります。

a.outが2つになりました。元からあった方(PID 10226)が親プロセス、新しくできた方(PID 10235)が子プロセスとなります。

プロセスを分けた後もなにもしなければプログラムは同じルートを通ります。

/* プロセス起動の例 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char* argv[]){
	printf("A\n\n");

	fork();
  
	puts("B");

	return 0;
}

プロセスを分ける前にAが出力され、プロセスが分けられた後、両方のプロセスでBが出力されます。これではどちらが親でどちらが子か分かりません。

親プロセスと子プロセスとで処理を分けるにはforkの戻り値を利用します。

/* プロセス起動の例 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char* argv[]){
	pid_t p;
	printf("A\n\n");

	p = fork();
  
	printf("B %d\n",p);

	return 0;
}

プロセスforkの戻り値が親プロセスと子プロセスとで異なるため、Bの後ろの数字が異なります(子プロセスは0となります)。

これを利用して次のように処理を分けることができます。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char* argv[]){
	int i,j,k;
	pid_t p;

	j = 50;
	p = fork();
	if(p == 0){ /* 子プロセス */
		for(i=0;i<5;i++){
			/* 1秒ごとにAAAとjを加算した値を出力する */
			printf("AAA %d\n",j++);
			sleep(1);
		}
	}
	else(p > 0){ /* 親プロセス */
		for(k=0;k<5;k++){
			/* 1秒ごとにBBBとjを減算した値を出力する */
			printf("BBB %d\n",j--);
			sleep(1);
		}
	}
	else(p == -1){
		/* エラー */
	}
	return 0;
}

1秒ごとにスリープしているので、同時に2つのプロセスが動いていることが分かります。jは変数名称は同じですが、プロセスが違うので片方は足される一方、もう片方は引かれる一方となります。

戻る