fork()の挙動がいまいち良く分からないので質問させてください。
自分はPHPでなのですが、fork()はCで使われるのが多いだろうということと、概念を知りたいとの事でこちらで質問させていただきました。
以下のように書きLinuxの端末にて実行しました。
目的は、
1. 2つの子プロセスを作り、それらを同時並行処理したい
2. 同時並行処理なので3秒後に処理を終わらせて出力したい
という事です。
#!/usr/local/bin/php -q
<?php
$time = time();
$pid = pcntl_fork();
if ($pid == 0) {
$j;
for ($j=0; $j < 3; $j++) {
printf("child1: %d\n", $j);
sleep(1);
}
} else if($pid > 0) {
pcntl_wait($status);
print ("Parent-a\n");
} else {
die('fork できません');
}
$pid = pcntl_fork();
if ($pid == 0) {
$i;
for ($i=0; $i < 3; $i++) {
printf("child2: %d\n", $i);
sleep(1);
}
} else if($pid > 0) {
pcntl_wait($status);
print ("Parent-b\n");
} else {
die('fork できません');
}
echo "time:" . (time() - $time) . "sec\n";
すると、6秒後にまず
child1: 0
child1: 1
child1: 2
child2: 0
child2: 1
child2: 2
time:6sec
child1: 0
child1: 1
child1: 2
Parent-b
time:6sec
が出力され、その3秒後に
Parent-a
child2: 0
child2: 1
child2: 2
time:9sec
Parent-a
Parent-b
time:9sec
が出力されました。
分からない点は以下の通りです。
1. Parent-bがParent-aより前に表示されたり、
child1: 0 child1: 1 child1: 2 child2: 0 child2: 1 child2: 2
及びParent-a Parent-bを出力したいのに、
なんかそれ以外のものが色々と不思議な順序で出力されている上、
9秒も処理時間にかかり、並行処理ではなく逐次処理になっているように見える。
2. 確か"Unix/Linuxプログラミング理論と実践"だったと思うのですが、Unix系の本にて
子作成(親のコピー) -> 子処理中、親は居眠り -> 子exit() -> 親wait() -> 親起きる
という感じで書かれていたように思いますが、
実行例のParent-a等を見ると、挙動が分かりません。
長くなり申し訳ございませんが、もし宜しければ間違っている点をご指摘していただけないでしょうか?
また、上記に書いた"目的"を実現するためのCなどで宜しいですのでコード例など部分だけで宜しいですので挙げて頂けたら幸いです。
申し訳ございませんが、宜しくお願いいたします。
A 回答 (4件)
- 最新から表示
- 回答順に表示
No.4
- 回答日時:
他の方が回答されているように、
親子の両プロセスがそれぞれ2回目のfork()で枝分かれしている点、
それから1つ目の子プロセスを wait() してから、
2つ目の子プロセスを fork() している点が問題です。
子プロセスの処理を関数にして分離すると
わかりやすいかもしれません。
↓
--
function child_proc($no){
for( $i = 0; $i < 3; $i++ ){
printf( "child%d: %d\n", $no, $i ); sleep( 1 );
}
exit( 100 + $no );
}
$pid1 = pcntl_fork();
if( $pid1 < 0 ){ die( "fork 1: error." ); }
if( $pid1 == 0 ){ child_proc( 1 ); }
$pid2 = pcntl_fork();
if( $pid2 < 0 ){ die( "fork 2: error." ); }
if( $pid2 == 0 ){ child_proc( 2 ); }
pcntl_waitpid( $pid1, $s );
printf( "(exit1) %d\n", pcntl_wexitstatus( $s ) );
pcntl_waitpid( $pid2, $s );
printf( "(exit2) %d\n", pcntl_wexitstatus( $s ) );
ありがとうございましたッ!
ちょっと変更しましたが、同様の記述をして、無事に自分のやりたかった事を実現できました。
本当にありがとうございました。
No.3
- 回答日時:
>親プロセスはchild2のように子プロセス処理が終わる度に、
>"pid>0"の処理を上から行う事になるのでしょうか?
child2の動作を誰もそういう風に説明してないですが・・・
前の説明よく見直してください。
説明としては#1のが詳しいですからそちらもよく読んでください。
>"Parent-a"が何故2回も出力されるのか分かりません。
バッファリングが関係しそうな気はしますがphpのバッファリング制御の事は
私わかりませんので、頑張って調べてください。
>また、時間も6秒かかっております。
child1が終了する(開始から3秒後)のを待ってから
child2をforkするように書かれてますので最低でも6秒かかるのは当然ですよ。
child1とchild2を並列動作させたいならCだとこんな感じ
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int
main(int argc, char **argv)
{
pid_t child_pids[2];
for (int i = 0; i < sizeof(child_pids) / sizeof(child_pids[0]); i++) {
child_pids[i] = fork();
if ((int)child_pids[i] == -1) {
perror("fork()");
return 1;
}
else if (child_pids[i] == 0) {
for (int j = 0; j < 3; ++j) {
printf("child%d: %d\n", i, j);
sleep(1);
}
_exit(0);
}
else {
/* no-op */
}
}
while (1) {
pid_t pid;
int status;
int finished;
finished = 0;
pid = wait(&status);
for (int i = 0; i < sizeof(child_pids) / sizeof(child_pids[0]); i++) {
if (child_pids[i] == pid)
child_pids[i] = 0;
if (child_pids[i] == 0)
finished++;
}
if (finished == sizeof(child_pids) / sizeof(child_pids[0]))
break;
}
return 0;
}
>child2の動作を誰もそういう風に説明してないですが・・・
すみません、Parent-aが2度も出来てきたので、そうなのかなぁ、と思いまして書かせていただきました
コードの記述、ありがとうございました。
やはり、wait()の記述がミソだと言うことが分かりました。
本当にありがとうございました。
No.2
- 回答日時:
>2. 確か"Unix/Linuxプログラミング理論と実践"だったと思うのですが、Unix系の本にて
>子作成(親のコピー) -> 子処理中、親は居眠り -> 子exit() -> 親wait() -> 親起きる
>という感じで書かれていたように思いますが、
その書籍は読んだことありませんが、
「子処理中、親は居眠り」はおかしいですね。
「親wait()で子exit()まで居眠り」が正しいです。
>実行例のParent-a等を見ると、挙動が分かりません。
子exit()は明示的に書かないといけないですよ?
例に書かれているものはそれがないので
child1がchild2のfork()までしてます。
ご回答ありがとうございました。
確かにサンプルではexit()が抜けておりました。
ご指摘ありがとうございます。
$pid1 = pcntl_fork();
if ($pid1 == 0) {
$j;
for ($j=0; $j < 3; $j++) {
printf("child1: %d\n", $j);
sleep(1);
}
echo "現在のプロセスID=" . posix_getpid() . "\n";
exit();
} else if($pid1 > 0) {
pcntl_wait($status);
print ("Parent-a\n");
} else {
die('fork できません');
}
のように変えたら挙動が変わりました。
しかし、
child1: 0 child1: 1 child1: 2
現在のプロセスID=4504
Parent-a
child2: 0 child2: 1 child2: 2
現在のプロセスID=4505
Parent-a Parent-b
time:6sec
のようになります。
親プロセスはchild2のように子プロセス処理が終わる度に、
"pid>0"の処理を上から行う事になるのでしょうか?
"Parent-a"が何故2回も出力されるのか分かりません。
また、時間も6秒かかっております。
この場合、どの部分にchild2の処理(pid2=fork()以下)を書けば3秒で終わるようになるのでしょうか?
No.1
- 回答日時:
動きは多分こんなところ。
具体的なプロセスIDを表示するようにしたら、デバッグが楽になると思ます。親プロセス
|
【分岐】―子プロセス1
| |
【待ち】 |
: 【処理1】
: |
: 【分岐】―子プロセス2
: | |
: 【待ち】 |
: : |
: : 【処理2】
: : |
: 【再開】←【時間表示後終了】
: |
【再開】←【時間表示後終了】
|
【分岐】―子プロセス3
| |
【待ち】 |
: 【処理2】
: |
【再開】←【時間表示後終了】
|
【時間表示後終了】
非常に分かりやすい図を記述して頂きまして有難うございました。
視覚的に理解できました。
No.2でのwormholeさんのご指摘にあったようにexit();を加えたら変な挙動はおさまりました。
ただ、Parent-aが2回表示されているのですが、何故このような挙動になるのかは分かりません。
上記図のように、親プロセスは上から下へと向かうのではなく、wait()の際かなにかに戻るような事もあるのでしょうか?
それと、child1とchild2を同時並列処理をさせるには、親プロセスの
最初の【待ち】--->【再開】の中に入れこまなくてはいけないのではと思いますが、
fork()した、その下にもう一度fork()を2回打って・・・とか考えたのですが、頭が少し混乱してきました(苦笑)
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- JavaScript clear機能を失わずにファイルアップロード機能を作成したい 3 2023/06/10 16:12
- その他(プログラミング・Web制作) seleniumbasic chrome操作について 1 2023/03/29 15:40
- 英語 分詞、形容詞的用法の完了形 9 2023/08/18 11:21
- 英語 「子供の頃の大好物」等の『「~の頃の」+名詞』の表現について 8 2022/04/28 11:36
- HTML・CSS html/cssで要素が出てこなくて困ってます 1 2022/12/31 16:59
- PHP PHPでCookieを使った訪問回数について 1 2023/05/28 14:10
- PHP PHPの変わった閉じタグの必要性と意味を教えてください。 1 2022/08/28 15:15
- 英語 What do you think a sick child needs most during t 3 2023/04/03 09:23
- HTML・CSS PCサイズで赤い画像2つと、青い画像2つがそれぞれ横に2つずつ並んでいるのですが、これをスマホサイズ 5 2022/04/11 12:01
- CGI perlで書いたcgiでsqliteの使い方を教えてください 2 2023/05/08 21:29
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
バックグラウンドのプロセスの...
-
explorer.exeが異様にメモリを食う
-
プロセスのアタッチ・デタッチ...
-
Texについてです。 jpgファイル...
-
WINのタスクマネージャの強制終了
-
シェルで親プロセス終了時に子...
-
ウィンドウのタイトルからプロ...
-
Linuxでのスレッド間メッセージ...
-
C++のプログラムをバックグラウ...
-
他のアプリケーションの操作に...
-
API関数 GetExitCodeProcess
-
怪しいプロセス教えてください。
-
WebBrowserでPDF表示でのトラブル
-
Windowsでのfork方法
-
ADOでアクセスのレコードに...
-
Visual C++からpingを実行して...
-
VBでエクセルを起動し、プロ...
-
スレッド?
-
VB6.0 SHELLで起動...
-
複数同時実行時の参照先について
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
バックグラウンドのプロセスの...
-
explorer.exeが異様にメモリを食う
-
なぜ女性は男性が忘れたことを...
-
タスクマネージャーのプロセス...
-
プロセスのアタッチ・デタッチ...
-
非表示になったエクセルは?
-
Process.Startの戻り値を後で取得
-
C#でのbatファイル実行結果取得
-
プロセスIDからウィンドウハ...
-
c言語でプロセスIDを調べたい
-
Linuxでのスレッド間メッセージ...
-
プロセスIDの取得方法について
-
ADOでアクセスのレコードに...
-
怪しいプロセス教えてください。
-
vb.netでEXCEL起動がうまくでき...
-
別のプロセスの関数を呼び出す...
-
C++のプログラムをバックグラウ...
-
Visual C++からpingを実行して...
-
VBS(WSH)で開いたIEのウィンド...
-
IISがフリーズ
おすすめ情報