perl - 查询: Loops in Relation to Parent - Child - Fork - Pids

标签 perl loops fork parent-child

我正在尝试学习 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

我遇到了一些我不太明白的问题。

  1. 它没有正确退出循环 - 它退出但在没有上下文的情况下继续(在按下回车键(又名“\n”)后输出底部有 4 个空行 - 它没有)继续访问 print "parent: the child pid with ......exit;

  2. 当我在 <STDIN> 之前添加一行时前任。 print "Enter something here: " 它不会重复该行作为循环的一部分 - 使得可读性不齐平。

感谢您提供的信息。

最佳答案

这里的主要问题是关闭管端。直接错误大概是WRITEPIPE

所有管道的末端必须在所有看到它们的进程中关闭。否则,管道上可能会留下一些东西,而另一端却忘记了。来自 Avoiding pipe deadlocks in perlipc

Whenever you have more than one subprocess, you must be careful that each closes whichever half of any pipes created for interprocess communication it is not using. This is because any child process reading from the pipe and expecting an EOF will never receive it, and therefore never exit. A single process closing a pipe is not enough to close it; the last process with the pipe open must close it for it to read EOF.

在这种情况下,子进程关闭 WRITEPIPE它读取(父级写入的内容)之后,因此父级在其 WRITEPIPE 上没有 EOF当需要时,因此永远不会放弃它。您需要Ctrl+C停止。简单搬家close WRITEPIPE之前child(...)让程序按预期工作。

同样令人震惊的是, child 永远不会关闭READPIPE (并且永远不会退出)。

还有其他问题,一些是风格问题,还有一些编译错误。这是一个工作程序,尽可能少地进行更改,具有相同的名称和简化的打印

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]

注意:if ($input eq "\n")中的消息只对下一次运行有好处,因为您还有 last在那里,退出STDIN在空线上。当节目开始时,使用消息位于顶部。

我简化了打印内容以使其更具可读性。如果您不喜欢这些,请将您的复制回来。

评论

  • 首先关闭每个进程中不需要的管道末端

  • 使用词法文件句柄,它们更好(my $reader而不是READER等)

  • 无需测试defined在 child 身上,因为您在 // 很好地使用了定义或( fork )

  • 所需的一项测试通常是针对 child 的,if ($pid == 0)

  • child 正常exit s,所以在子进程阻塞之后只剩下父进程

  • 对于您想要处理的进程之间的任何写入/读取SIGPIPE 。请参阅下面的文档

  • 您需要检查退出状态、错误等。请参阅下面的文档。

文档:perlipc , forkexec , perlvar (在 $?$!%SIG 上)、 pipe 和链接

必须仔细阅读perlipc的许多部分。 (以及其他文档)。

关于perl - 查询: Loops in Relation to Parent - Child - Fork - Pids,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42637520/

相关文章:

php - 如何将我的 Perl 脚本与 MySQL 查询同步

linux - clone() 系统调用是否最终依赖于 fork 功能?

api - fork() 与 CreateProcess()。系统调用与 API?

regex - Perl 正则表达式 : Matching text with optional multi-line

perl - 解析时我没有得到 HTML 标签

perl - 使用 WWW::Mechanize 保存 PDF 文件会损坏它们

r - R中的填充系列

c - 如何在给定的数字集合中找到第二大元素?

Python-循环遍历未排序的数组时计算某一项的出现次数

C用fork()编写后关闭FDT?