2017-03-06 5 views
1

私は、perlの親、子、パイプの機能を習得しようとしています。私の目標は、コマンドラインから読み取ってパイプを介して出力する単一のパイプ(双方向ではない)を作成することです。 pidを何度も参照する。お問い合わせ - 親/子供/フォーク/ Pidに関連するループ

これまでコード:

#!/usr/bin/perl -w 

use warnings; 
use strict; 


pipe(READPIPE, WRITEPIPE); 
WRITEPIPE->autoflush(1); 
STDOUT->autoflush(1); 

my $parentpid = $$; 
my $childpid = fork() // die "Fork Failed $!\n"; 

# This is the parent 
if ($childpid) { 
    &parent ($childpid); 
    close READPIPE; 
    close WRITEPIPE; 
    waitpid ($childpid,0); 
    print "Parent: The child pid with a pid of: $childpid as stopped, and the parent with the pid: $parentpid has stopped.\n"; 
    exit; 
} 
# This is the child 
elsif (defined $childpid) { 
    &child ($parentpid); 
    close WRITEPIPE; 

} 

else {} 

sub parent { 
    while(1){ 
     my $input = <STDIN>; 
     if ($input eq "\n"){print "Undef- CRTL+C = Quit\n", last;} 
     else { 
      print "ParentSub: The parent pid is: ",$parentpid, " and the message being received is: ", $input; 
      print WRITEPIPE "$input"; 
      print "ParentSub: My parent pid is: $parentpid\n"; 
      print "ParentSub: My child pid is: $childpid\n";  
      } 
     } 
} 

sub child { 
    while ($line = <READPIPE>){ 
     print "ChildSub: The child pid is: " $childpid,"\n"; 
     print "ChildSub: I got this line from the pipe: ",$line," and the child pid is ",$childpid,"\n"; 
           } 
} 

電流出力は次のようになります。

Hello World 
ParentSub: The parent pid is: 2633 and the message being received is: Hello World 
ParentSub: My parent pid is: 2633 
ParentSub: My child pid is: 2634 
ChildSub: The child pid is: 0 
ChildSub: I got this line from the pipe: Hello World 
, and the child pid is 0 

私はかなり理解していないいくつかの問題に実行しています。

  1. それは、ループは、それが終了したがいない状況での続くproperly-終了しない(そこに入力したキー(別名「\ n」)を打つからの出力の下部後4つの空白行が - それはdoesnの私は<STDIN> EXの前に行を追加すると「tはprint "parent: the child pid with ......exit;

  2. に進む。print "Enter something here: " を、それが可読性がフラッシュではない作るLOOP-の一環として、その行を繰り返していません。

T情報のハンクス。

答えて

2

ここでの主な問題は、パイプの端を閉じることです。直接の誤差は約WRITEPIPEです。

すべてのパイプの端は、それらを参照するすべてのプロセスで閉じる必要があります。そうしないと、相手が忘れてしまったパイプで何かが待っているかもしれません。からAvoiding pipe deadlocks in perlipc

複数のサブプロセスがある場合は、プロセス間通信のために作成されたパイプのうち半分が使用していないものを閉じるように注意する必要があります。これは、パイプから読み込んでEOFを期待する子プロセスがそれを受け取ることはないため、決して終了しないためです。パイプを閉じている1つのプロセスだけではそれを閉じることはできません。パイプが開いている最後のプロセスは、EOFを読み取るためにパイプを閉じる必要があります。この場合

子供はそれが(書き込みを何親)を読み取り、その必要なときに親がそのWRITEPIPEにEOFを持っていないので、それを終了したことがないだけWRITEPIPEを閉じます。停止するにはCtrl+Cが必要です。単にをchild(...)の前に移動するだけで、プログラムは意図したとおりに動作します。

子どもが決してREADPIPEを閉じない(そして決して退出しない)ことは印象的です。

他にもいくつかの文体があり、いくつかのコンパイルエラーがあります。if ($input eq "\n")でのメッセージはあなたから、次の実行のための唯一の良いです:ここでの作業プログラムは、同じ名前と単純化されたプリント

use warnings; 
use strict; 
#use IO::Handle; # need this on pre-v5.14 (?) versions for autoflush 

pipe (my $readpipe, my $writepipe); 

$writepipe->autoflush(1); 
STDOUT->autoflush(1); 

my $parentpid = $$; 
my $childpid = fork() // die "Fork failed $!\n"; 

# This is the child 
if ($childpid == 0) { 
    close $writepipe; # child reads 
    child ($parentpid); 
    close $readpipe; 
    exit; 
} 
# This is the parent 
close $readpipe;  # parent writes 
parent ($childpid); 
close $writepipe; 
waitpid $childpid, 0; 
print "Parent: child $childpid exited, parent $parentpid done.\n"; 

sub parent { 
    while (1) { 
     my $input = <STDIN>; 
     if ($input eq "\n") { print "Undef- CRTL+C = Quit\n", last; } 
     else { 
      print "ParentSub: parent $parentpid got the message: ", $input; 
      print $writepipe "$input"; 
      print "ParentSub: parent pid is $parentpid\n"; 
      print "ParentSub: child pid is $childpid\n";   
     } 
    } 
} 

sub child { 
    while (my $line = <$readpipe>) { 
     print "ChildSub: child pid is $childpid\n"; 
     print "ChildSub: got from the pipe: $line"; 
    } 
} 

プリント

 
hello [Entered at STDIN] 
ParentSub: parent 22756 got the message: hello 
ParentSub: parent pid is 22756 
ParentSub: child pid is 22757 
ChildSub: child pid is 0 
ChildSub: got from the pipe: hello 

Parent: child 22757 exited, parent 22756 done. [After Enter at STDIN] 

注意して、可能な限り小さな変化に、ありますまたemtpyライン上STDINを終了するには、そこにlastを持っています。ショーが始まると、使用メッセージが上に表示されます。

私は読みやすくするためにプリントを簡略化してきました。あなたがこれらを気に入らなければ、あなたを元に戻してください。

コメント

  • 遠かっ最初が各工程で

  • 使用語彙ファイルハンドルをパイプの不要な端部を閉じ、それらが(代わりREADERなどのmy $reader)良好である

  • なしあなたはうまく定義された、または(//)を使用するのでで子供にdefinedをテストする必要があります

  • 1つのに必要なテストが任意の書き込みでこれだけ親プロセスが子のブロックの後

  • まま、子供のために通常if ($pid == 0)

  • 子通常exit sは/あなたはプロセス間で読み込み、 SIGPIPEを処理します。以下のドキュメントを参照してください

  • 以下のドキュメントあなたは終了ステータスをチェックする必要があり、エラーなどを参照してください。

ドキュメント:perlipcforkexecperlvar$?$!、および%SIG上)、pipeをリンクします。

perlipc(他のドキュメントと一緒に)の多くの部分を慎重に参照することが義務付けられています。

+0

信じられないほどの情報。これを読む前に、私は教えている人の助けを借りてプログラムを終えましたが、あなたの答えからどのくらいの情報と理解が得られたのか信じられませんでした。優しい言葉をありがとう@The_Makings_Of_A_Coder –

+0

は、喜んでそれが:)に役立ちます。ドキュメントを徹底的に調べて、慎重に良い知識を集めてください。これは複雑で、ややこしい。頑張って楽しんでね :) – zdim

関連する問題