perlのwhile loop内のforkについて

このQ&Aのポイント
  • perlのfork機能を使いたい者ですが、その挙動について質問しています。
  • 質問内容を具体的にするため、以下に簡単なコードを書いておきます。
  • なぜ、「parent finish」が4回も出てくるのかということです。
回答を見る
  • ベストアンサー

perlのwhile loop内のforkについて

perlのfork機能を使いたい者ですが、その挙動について質問しています。 ここ数日fork機能について勉強しましたが、 その挙動がどうでしても理解できないので、質問をさせていただいています。 質問内容を具体的にするため、以下に簡単なコードを書いておきます。 #!/usr/bin/perl use strict; my $i=0; while ($i<3) { if(fork()) { print("parent hello -> $i\n"); last; } else { print("child hello -> $i\n"); sleep 3; print("child exit -> $i\n"); $i++; } } print("parent finish\n"); このコードをlinux上で起動させますと、下記の結果が得られました。 parent hello -> 0 parent finish child hello -> 0 child exit -> 0 parent hello -> 1 parent finish child hello -> 1 child exit -> 1 parent hello -> 2 parent finish child hello -> 2 child exit -> 2 parent finish ここから質問です。 上記の結果の中で自分が理解できないのは、 なぜ、「parent finish」が4回も出てくるのかということです。 自分の理解している部分では、「parent finish」はwhile loopの外にあるので、 「parent finish」をプリントするには、一度while loopを出る必要があると思います。 しかし、それが2、3回と続いてプリントされていることがなぜなのか理解できません。 理想としては、 parent hello -> 0 child hello -> 0 child exit -> 0 parent hello -> 1 child hello -> 1 child exit -> 1 parent hello -> 2 child hello -> 2 child exit -> 2 parent finish という具合に、「parent finish」を一回だけ表示させたいのですが、それは可能でしょうか? ご教授をお願いします。よろしくお願いします。

  • Perl
  • 回答数2
  • ありがとう数2

質問者が選んだベストアンサー

  • ベストアンサー
回答No.2

プロセスIDを付けると何がおこっているのかわかりますよ。 以下、$$はプロセスIDを表わしています。表示がくずれるので空白2文字を全角空白にし ていることに注意。 use strict; use warnings; my $i = 0; while ( $i < 3 ) {   if ( fork() ) {     print "parent($$) hello -> $i\n";     last;   }   else {     print "child($$) hello -> $i\n";     sleep 3;     print "child($$) exit -> $i\n";     $i++;   } } print "parent($$) finish\n"; --- $ perl -w foo.pl parent(24503) hello -> 0 parent(24503) finish child(24504) hello -> 0 child(24504) exit -> 0 parent(24504) hello -> 1 parent(24504) finish child(24510) hello -> 1 child(24510) exit -> 1 parent(24510) hello -> 2 parent(24510) finish child(24511) hello -> 2 child(24511) exit -> 2 parent(24511) finish

nagoyan_nagoyan
質問者

お礼

ありがとうございます。 確かにプロセスIDを表示するとわかりやすかったです。 理解した部分では、 fork -> プロセスが2つ作成される(ここでは、24503と24504)。 そのうちの一つ(24503)は、if statement内にある”parent(24503) hello -> 0”を経て、 lastがあるため、 while loopから抜け出て、最後の”parent(24503) finish”(ここでは、24503プロセスが終了している)がプリントされる。 先に作成された別のプロセス(24504)は、elseに入り、プリントを経て、$iをインクリメントして、while loopのチェックを受け、次につながる。 このため、複数回"parent($$) finish\n"がプリントされていたのですね。 勉強にもなりましたし、大変スッキリしました。 ありがとうございました。

その他の回答 (1)

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

ん~と, どこが不思議なのかわからんのだけど.... fork で生まれた子プロセスでも last してるよね.

関連するQ&A

  • fork()の挙動について質問させてください

    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などで宜しいですのでコード例など部分だけで宜しいですので挙げて頂けたら幸いです。 申し訳ございませんが、宜しくお願いいたします。

  • forkについて

    fork文を使った問題について質問です。 #include <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> int main() { pid_t pid1,pid2; if((pid1 = fork()) == 0) printf("I am a first child with pid = %d,My parent pid is %d.\n",getpid(),getppid()); else if(( pid2 = fork()) == 0) printf("I am a second child with pid = %d,My parent pid is %d.\n",getpid(),getppid()); else printf("I am a parent with pid = %d.\nMy first and second children are %d and %d.\n",getpid(),pid1,pid2); exit(EXIT_SUCCESS); } このようなプログラムが与えられました。 問題は 1.このプログラムを改造して、1つの親プロセスから100の子プロセスを順に生成するプログラムをつくるというものと 2.1つの親から子プロセスを生成し、その子プロセスの孫プロセスを生成するプログラムをつくれというものです。 1はfor文を使えばできそうなのですが、forkの基礎が出来ていないのでどうループを回せばよいか分かりません。 2もfork内でforkを実行すればできそうだと思ったのですがうまく動かず・・・。 どうか正しく動くようなプログラムを教えてください!お願いします。

  • Perlのforkについて

    PerlでDBに格納するプログラムを作成しています。 パラレルで行ないたいためにforkを使っているのですが、 いまいちわかっていないのでご教授ください。 やりたいことはパラレルでのDB格納です。 親、子両方のプロセスが完了したら後続処理を行い、 0を戻したいのですが、下記の方法ですと、 子が終了したらprintしてからreturnしているようです。 このように、親子の処理が完了したら後続処理に移るようにするためには どうしたらよいのでしょうか? if ($pid = fork()) { #親プロセス insertDB(); wait; return 0; } else { insertDB(); } print"ここは最後に通したい"\n;

    • ベストアンサー
    • Perl
  • perlのprint文がうまく動きません

    perlの勉強を始めました。 perlの本の最初に Hello.plというファイルに print”Hello!”;と記述して perl Hello.plとすると画面にHello!と表示されるとあるのですが、何も表示されません。 ファイルの記述をprint ”Hello!\n";としてやるとHello!と一応表示されるのですがなぜ改行が必要になるのかがよくわかりません。どのように理解すればいいのでしょうか?

  • Perlの並列処理

    私は今Perlの並列処理について学んでいます。3並列で子プロセスが行う処理はa1、a2、a3、・・・ak(処理にかかる時間a1<a2<a3<・・・)で、親プロセスはa1、a2、a3、・・・の結果を判定するというものです。 a1、a2、a3と順に判定していきたいと考えているのですが、どのようなプログラムを書けばよいでしょうか。なお、並列処理にはforkを利用するつもりです。 一度以下のようなプログラムを考えたのですが、これだとa1→a3→・・・→ak→親プロセス→a2→a4→・・・→a(k-1)→親プロセスとなってしまいます。よろしくお願いします。 while($count--){ #$countは並列数を入力   my $pid =fork;   &child_process;   exit; } wait; 【親プロセス】 sub child_process{   while($n<k){     $n=1;     【処理a$nを行う】     $n=$n+$count;     }   exit; }

  • forkで作れる子プロセス数が限られている

    for($i=0;$i<1000;$i++) { if($p=fork) { next; } elsif(defined($p)) { sleep 10000; exit; } else { print("$i\n"); <STDIN>; } } 数十個で子プロセスが生成されなくなります メモリは十分あまってます デスクトップヒープ領域が足りなくなったわけじゃなさそうです どうすればメモリが足りる限り子プロセスを生成できるでしょうか? windows xp avtive perl 5.8.7です。

    • ベストアンサー
    • Perl
  • perl入門

    Perl のコマンドラインハッシュで 1.引数指定 perl -e "print 'Hello world!!';" 2.標準入力読み込み echo print "Hello World!!\n" と言うのがありますが違いがよくわかりません。 引数という言葉の意味もよくわかりません。 初歩的な質問ですがよろしくお願いします。

    • ベストアンサー
    • Perl
  • PHPとPerlのリダイレクト

    こんにちは。 PHPとPerlのリダイレクトの処理ついて質問です。 PHPのリダイレクトには、exit;を付けないとその後の処理も行ってしまいます。 header("Location:index.php"); exit; Perlのリダイレクトにも、このexit;は必要でしょうか? print "Location:index.cgi\n\n"; exit; ← ? 以上です。 どうぞよろしくお願いします。

    • ベストアンサー
    • Perl
  • fork()のpidとppid

    システムコールのfork()の勉強をしています。 fork()によって作られたプロセスのそれぞれのpidとppidを知りたいのですが頭がこんがらがってしまいました。 「forkシステムコールは親プロセスには作成された子プロセスのプロセスIDが、子プロセスには0が返る」とあったので以下のコードの場合 pid = fork(); if(pid == 0) printf("%s, child process\n", msg); else printf("%s, parent process\n", msg); 子のpidが0のためifが実行され、親はelseが実行される というところまで理解できたのですが このとき親のpidは子のID、子のpidは0なのでしょうか? 教科書の図(添付)を見ると親のpidは0で子、孫になるにつれてpidが大きくなっていてよくわからなくなってしまいました。 例えば以下のようなコードがあった場合、 pid_t pid; // メインプロセスのPIDは42 pid = fork(); // プロセスをPID=11で作成 if (pid == 0) { pid_t pid2 = fork(); // プロセスをPID=25で作成 if (pid2 == 0) { sleep(20); exit(0); } waitpid(pid2,NULL,0); exit(0); } else { pid_t pid3 = fork(); // プロセスをPID=89で作成 if (pid3 == 0) { sleep(10); printf("** ONE **\n"); exit(0); } pid_t pid4 = fork(); // プロセスをPID=123で作成 if (pid4 == 0) { sleep(30); printf("** TWO **\n"); exit(0); } } sleep(20); exit(0); それぞれのプロセスのpidとppidはどうなるのでしょうか? 説明がうまくできないのですが、 分かる方いましたら回答よろしくお願いします。

  • perlのdo-while文で抜け出せない 

    perlのwhile,do-while,last文に関する質問です。 1) code1のようなプログラムを作ったのですが   eでdo_whileを抜け出すことができませんがなぜでしょうか。 ---code1(eで抜け出せない)(NG)--- my $sum=0; do{  my $a=<STDIN>;  chomp($a);  $sum=$sum+$a; }while($a ne 'e'); print $sum; -------------------------------- 2) 抜け出す方法をいろいろ試していたら   while(1)にしてlastで抜けるようにすると   code2ではeで抜け出すことができるように   なりましたが、   do~while(1)にしたcode3では、  「Can't "last" outside a loop block at …」C   というエラーが発生します。   code2とcode3はwhileがdo~whileになって   条件を見る位置がループの始めか終わりの   違いだけなのに、なぜ、code2ではOKで、   code3ではエラーになるのでしょうか。 ---code2(eで抜け出せる)(OK)----- my $sum=0; while(1) {  my $a=<STDIN>;  chomp($a);  last if ($a eq 'e');  $sum=$sum+$a; }; print $sum; --------------------------------- ---code3(エラーになる)(NG)----- my $sum=0; do{  my $a=<STDIN>;  chomp($a);  last if ($a eq 'e');  $sum=$sum+$a; }while(1); print $sum; --------------------------------- よろしくお願いします。 Windows7 , ActivePerl(v5.16.3)

    • ベストアンサー
    • Perl

専門家に質問してみよう