🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

3回答

4208閲覧

C言語でfork()がどのような順番で実行されているのかを知りたい

patama

総合スコア18

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2019/12/16 12:01

C言語でfork関数を使い、PIDをそれぞれ表示する以下のプログラムを作成したのですが、結果が

PARENT_PID = 4383

CHILD_PID_3 = 4386
CHILD_PID_2 = 4385
CHILD_PID_1 = 4384

という順番になり、実行順がどうも納得いきません。最初の

  pid_a = fork();

で返り値に0を受け取った子プロセスが

else if(pid_a == 0){
printf("CHILD_PID_1 = %d\n",getpid());
sleep(2);
}

で引っかかって

CHILD_PID_1 = 4384

が最初に表示されると思っていたのですが、何度やっても上記の実行結果になります。

何か実行順に決まりがあるのでしょうか?

c

1#include<stdio.h> 2#include<unistd.h> 3 4int main(void){ 5 pid_t pid_a,pid_b,pid_c; 6 7 pid_a = fork(); 8 9 if(pid_a == -1){ 10 fprintf(stderr, "fork has failed.\n"); 11 sleep(2); 12 }else if(pid_a == 0){ 13 printf("CHILD_PID_1 = %d\n",getpid()); 14 sleep(2); 15 }else{ 16 pid_b = fork(); 17 if(pid_b == -1){ 18 fprintf(stderr, "fork has failed.\n"); 19 sleep(2); 20 }else if(pid_b == 0){ 21 printf("CHILD_PID_2 = %d\n",getpid()); 22 sleep(2); 23 }else{ 24 pid_c = fork(); 25 if(pid_c == -1){ 26 fprintf(stderr, "fork has failed.\n"); 27 sleep(2); 28 }else if(pid_c == 0){ 29 printf("CHILD_PID_3 = %d\n",getpid()); 30 sleep(2); 31 }else{ 32 printf("PARENT_PID = %d\n",getpid()); 33 sleep(2); 34 } 35 } 36 } 37 38 return 0; 39}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

あなたが、
CHILD_PID_1 = xxxx
CHILD_PID_2 = xxxx
CHILD_PID_3 = xxxx
PARENT_PID = xxxx
のようになることを期待していたのは、
「プログラムは上から順に実行される」ため、その順になると考えたのかと想像します。
もちろん、それであっていますが、forkした後はプログラム(プロセス)が2つに分かれ、2つ同時に
実行されます。
図でいうと①の個所からプログラムが2つ同時に走ります、(②、③も同様)
ソース上では①、②、③の個所になります。
①、②、③は親プロセスと子プロセスで別々に実行されることに注意してください。
その時、どちらのプログラムが先に実行されるかは、他の方のおっしゃる通りで、OSの制御に依存し、どちらが先になるかはわかりません。

添付図

もし、あなたが
CHILD_PID_1 = xxxx
CHILD_PID_2 = xxxx
CHILD_PID_3 = xxxx
PARENT_PID = xxxx
となることを期待するなら
以下のように追加①、追加②、追加③の行を追加してください。
そこで意図的にスリープするので、子プロセスが必ず先に実行されます。

C

1#include<stdio.h> 2#include<unistd.h> 3 4int main(void){ 5 pid_t pid_a,pid_b,pid_c; 6 7 pid_a = fork(); 8 9 if(pid_a == -1){ ・・・・・・・・・・・・・・・① 10 fprintf(stderr, "fork has failed.\n"); 11 sleep(2); 12 }else if(pid_a == 0){ 13 printf("CHILD_PID_1 = %d\n",getpid()); 14 sleep(2); 15 }else{ 16 sleep(1);・・・・・・・・・・・・・・・・・・・・・追加① 17 pid_b = fork(); 18 if(pid_b == -1){・・・・・・・・・・・・・・・・・② 19 fprintf(stderr, "fork has failed.\n"); 20 sleep(2); 21 }else if(pid_b == 0){ 22 printf("CHILD_PID_2 = %d\n",getpid()); 23 sleep(2); 24 }else{ 25 sleep(1);・・・・・・・・・・・・・・・・・・・追加② 26 pid_c = fork(); 27 if(pid_c == -1){・・・・・・・・・・・・・・・③ 28 fprintf(stderr, "fork has failed.\n"); 29 sleep(2); 30 }else if(pid_c == 0){ 31 printf("CHILD_PID_3 = %d\n",getpid()); 32 sleep(2); 33 }else{ 34 sleep(1);・・・・・・・・・・・・・・・・・追加③ 35 printf("PARENT_PID = %d\n",getpid()); 36 sleep(2); 37 } 38 } 39 } 40 41 return 0; 42}

投稿2019/12/17 03:02

tatsu99

総合スコア5493

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

rubato6809

2019/12/17 07:38

図を示したのが良いですね。
patama

2019/12/23 14:23

なるほど!ありがとうございました!
guest

0

fork() すれば新たに子プロセスが作られ、fork() 直後のコードを走るプロセスが2つになる・・・そこは分かってると思う。さて親と子、2つのプロセスがあるということは、親プロセスも子プロセスも、その他の(たぶんアクティブな)プロセスも、OS内部のプロセスキューに並んでいる状態です。その時、親と子、どちらが先に動くか、それはC言語の問題ではなくて、OSのプロセススケジューリングの問題です。そのプログラムの問題というより、OSの問題だということを強調します。

なので、ご使用のOS・動作環境を明らかにして、その筋の質問として問いなおすと良いかもしれません。現在だとCPUのコア数が関係するかもしれません。

ちなみに、そのコードを私の手元で動かしてみると、その都度表示の順番が変化しました。私のPCのOSはLinux(Ubuntu 16.04)です。

sh

1$ ./a.out 2PARENT_PID = 26949 3CHILD_PID_1 = 26950 4CHILD_PID_2 = 26951 5CHILD_PID_3 = 26952 6$ ./a.out 7CHILD_PID_1 = 26959 8PARENT_PID = 26958 9CHILD_PID_2 = 26960 10CHILD_PID_3 = 26961 11$ ./a.out 12PARENT_PID = 26963 13CHILD_PID_2 = 26965 14CHILD_PID_1 = 26964 15CHILD_PID_3 = 26966 16$ ./a.out 17PARENT_PID = 26967 18CHILD_PID_2 = 26969 19CHILD_PID_3 = 26970 20CHILD_PID_1 = 26968 21$ ./a.out 22CHILD_PID_1 = 26972 23PARENT_PID = 26971 24CHILD_PID_2 = 26973 25CHILD_PID_3 = 26974

投稿2019/12/16 13:03

編集2019/12/16 13:49
rubato6809

総合スコア1382

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

Cというより、OSの問題です。順序がどうなるかは決まっていません。
他のプロセスのコア使用状態などによって、同じ環境で繰り返し実行しても違う結果になるかと思います。

お書きの結果は、親プロセスが連続してCPUをもらい続けたということでしょう。

投稿2019/12/16 12:25

otn

総合スコア85891

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問