查询-与父母/孩子/叉子/孩子有关的循环 [英] Inquiry- Loops in Relation to Parent/Child/Fork/Pids

查看:65
本文介绍了查询-与父母/孩子/叉子/孩子有关的循环的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试学习perl中的父母,孩子和烟斗的功能.我的目标是创建一个从命令行读取并通过管道打印的管道(非双向).多次引用pid.

I am attempting to learn the functionality of parents, children and pipes in perl. My goal is to create a single pipe (not bidirectional) that reads from the command line, and prints it through a pipe. Referencing the pids many many times.

到目前为止的代码:

#!/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

我遇到了一些我不太了解的问题.

I am running into a few issues that I don't quite understand.

  1. 它没有正确退出循环-退出但没有上下文继续(敲击回车键(又名"\ n",输出的底部之后有4个空行)-它没有t进入print "parent: the child pid with ......exit;

当我在<STDIN> ex之前添加一行时. print "Enter something here: " 它不会重复该行作为循环的一部分,从而使可读性不趋于齐平.

When I add a line in before the <STDIN> ex. print "Enter something here: " it doesn't repeat that line as part of the loop- making readability not flush.

感谢您提供信息.

推荐答案

此处的主要问题是关闭管道末端.直接错误约为WRITEPIPE.

The main problem here is with closing the pipe ends. The direct error is about WRITEPIPE.

所有管道的端部必须在看到它们的所有进程中关闭.否则,可能会在另一端遗忘的管道上留下一些等待的东西.来自避免在perlipc中出现管道死锁

All pipes' ends must be closed in all processes that see them. Otherwise something may be left waiting on a pipe which the other end forgot about. From Avoiding pipe deadlocks in perlipc

无论何时有多个子进程,都必须注意,每个子进程都会关闭它为未使用的进程间通信而创建的所有管道中的一半.这是因为任何从管道读取并期望EOF的子进程将永远不会收到它,因此也永远不会退出.关闭管道的单个过程不足以将其关闭.管道打开的最后一个过程必须关闭它才能读取EOF.

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停止.只需在child(...)之前移动close WRITEPIPE即可使程序按预期工作.

In this case the child closes WRITEPIPE only after it reads (what parent writes), so the parent doesn't have the EOF on its WRITEPIPE when needed and thus never quits it. You need Ctrl+C to stop. Simply moving close WRITEPIPE before child(...) gets the program to work as intended.

引人注目的是,孩子永远不会关闭READPIPE(也永远不会退出).

It is also striking that the child never closes READPIPE (and never exits).

还有其他问题,有些是样式问题,还有一些编译错误.这是一个工作程序,变化不大,名称相同,打印内容简化

There are other issues, some of stylistic nature, and a few compilation errors. Here is a working program, with as little change as feasible, with same names and simplified prints

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.放映开始时,使用情况消息会排在最前面.

Note: the message in if ($input eq "\n") is only good for the next run, since you also have last there, to quit STDIN on emtpy line. Usage messages belong on top, when the show starts.

我简化了打印件,以提高可读性.如果您不喜欢这些,请将其复制回去.

I've simplified prints to be more readable. Copy yours back if you don't like these.

评论

  • 在每个过程中先关闭不需要的管道端

使用词汇文件句柄会更好(my $reader代替READER等)

Use lexical filehandles, they are better (my $reader instead of READER etc)

无需在子级上测试defined,因为您在fork

No need to test defined on child since you nicely used defined-or (//) at fork

一个所需的测试通常是儿童if ($pid == 0)

The one needed test is normally for child, if ($pid == 0)

孩子通常exit s,因此只有父进程保留在孩子的障碍之后

The child normally exits, so only the parent process remains after the child's block

要处理SIGPIPE的进程之间进行任何写入/读取.参见下面的文档

With any writes/reads between processes you want to handle SIGPIPE. See docs below

您需要检查退出状态,错误等.请参见下面的文档.

You need to check exit status, errors, etc. See docs below.

文档: perlipc exec perlvar (在$?$!%SIG上) ),管道 和链接.

Documentation: perlipc, fork and exec, perlvar (on $?, $!, and %SIG), pipe and links.

必须仔细检查 perlipc 的许多部分(以及其他文档)

It is compulsory to carefully go through many parts of perlipc (along with other docs).

这篇关于查询-与父母/孩子/叉子/孩子有关的循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆