我试图在perl中学习父母,孩子和管道的功能。我的目标是创建一个从命令行读取的单个管道(非双向),并通过管道打印它。多次引用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
我遇到了一些我不太了解的问题。
它没有正确退出循环 - 它退出但没有上下文继续(输入底部输入后输入4个空行(又名&#34; \ n&#34; ) - 它没有进入print "parent: the child pid with ......exit;
当我在<STDIN>
ex之前添加一行时。 print "Enter something here: "
它不会重复该行作为循环制作可读性不冲洗的一部分。
感谢您提供的信息。
答案 0 :(得分:2)
这里的主要问题是关闭管端。直接错误大约是WRITEPIPE
。
所有管道的末端必须在看到它们的所有进程中关闭。否则可能会有一些东西在另一端忘记的管道上等待。来自Avoiding pipe deadlocks in perlipc
每当有多个子进程时,必须小心每个子进程关闭为其未使用的进程间通信创建的任何管道的一半。这是因为从管道读取并期望EOF的任何子进程都将永远不会收到它,因此永远不会退出。关闭管道的单个过程不足以关闭它;管道打开的最后一个过程必须关闭它才能读取EOF。
在这种情况下,孩子只有在读取后才会关闭WRITEPIPE
(父写的内容),所以父母的{E>没有{E} {1}}在需要时,因此永远不会退出它。您需要WRITEPIPE
才能停止。只需在Ctrl+C
之前移动close WRITEPIPE
即可使程序按预期工作。
令人惊讶的是,孩子永远不会关闭child(...)
(并且永不退出)。
还有其他问题,一些风格性质和一些编译错误。这是一个工作程序,尽可能少改变,具有相同的名称和简化的打印
READPIPE
打印
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]
注意: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";
}
}
中的邮件仅适用于下次投放,因为您还有if ($input eq "\n")
,以便在emtpy线上退出last
。当节目开始时,用法消息属于顶部。
我简化了打印,使其更具可读性。如果你不喜欢这些,请复制你的。
评论
Aways first 在每个流程中关闭不需要的管道末尾
使用词汇文件句柄,它们会更好(STDIN
而非my $reader
等)
无需在儿童身上测试READER
,因为您在defined
//
)
所需的测试通常适用于儿童,fork
孩子通常if ($pid == 0)
,所以只有父程序在孩子的阻止后仍然存在
在要处理的进程之间进行任何写入/读取exit
。请参阅以下文档
您需要检查退出状态,错误等。请参阅下面的文档。
文档:perlipc,fork和exec,perlvar(位于SIGPIPE
,$?
和$!
), pipe 和链接。
必须仔细阅读perlipc的许多部分(以及其他文档)。