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は変数名称は同じですが、プロセスが違うので片方は足される一方、もう片方は引かれる一方となります。