perl:一位家长,许多孩子——家长中的单管阅读器? [英] perl: one parent, many children - single pipe reader in parent?

查看:37
本文介绍了perl:一位家长,许多孩子——家长中的单管阅读器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 perl 中是否有可能以这样一种方式建立一个管道,即父级只有一个 READER 管道并且许多孩子在生命/退出时写入它?

is it possible in perl to establish a pipe in such a way that the parent has only one READER pipe and many children write to it as they come to life/exit?

典型的食谱代码是:

#!/usr/bin/perl -w
# pipe2 - use pipe and fork so child can send to parent

use IO::Handle;
pipe(READER, WRITER);
WRITER->autoflush(1);

if ($pid = fork) {
    close WRITER;
    chomp($line = <READER>);
    print "Parent Pid $$ just read this: `$line'\n";
   // do what you need
} else {
    die "cannot fork: $!" unless defined $pid;
    close READER;
    print WRITER "Child Pid $$ is sending this\n";
    close WRITER;  # this will happen anyway
    exit;
}

让我们假设一种情况,我需要我的父母阅读器"从多个孩子那里获取消息,是否可以在不保留管道列表的情况下做到这一点,每个孩子一个?我无法在父级中关闭 WRITER,因为下一个子级将无法获得有效的写入句柄.我还需要父级继续其常规操作,而不是阻止来自管道的任何客户端数据.

Let's instead assume a case where I need my parent "READER" to get messages from multiple children, is it possible to do this without keeping a list of pipes, one per child? I can't close WRITER in the parent because the next child won't get a valid handle to write to. I also need the parent to continue its regular operation and not block on any client data from the pipe.

我需要的伪代码:

# parent code
pipe (READER, WRITER)
fork_random_number_of_children(READER,WRITER)

on_some_tick => {
    my $data = read_from(READER, non_blocking)
    if (data) print "Hey some child sent me: $data"
    else print "No data, going back life"
    do_other_things_before_next_tick()
}

child_job(R,W) { # lets assume this is called for each child fork
  close (R); # no problem, its a copy
  sleep (random duration)
  print W, "Message from child with pid $$"
  exit 0
}

推荐答案

我认为没有必要在父级中关闭 WRITER.这可能是一个很好的做法,但由于在关闭新的子进程后不能将同一个管道重用,这是一个不这样做的好借口.如果在启动所有子进程之前保持 WRITER 打开,则可以将管道与多个子进程重用.这是概念证明:

I don't think it's necessary to close WRITER in the parent. It may be a good practice, but since you can't reuse the same pipe for new child processes after you close it, that's a good excuse not to do it. If you keep WRITER open until you are done launching all your child processes, you can reuse the pipe with multiple child processes. Here's a proof of concept:

use IO::Handle;
use POSIX ':sys_wait_h';
pipe(READER,WRITER);
WRITER->autoflush(1);

sub child_process {
    my $stage = shift;
    close READER;  # also a best but optional practice
    srand($$);
    do {
        sleep 1 + 5*rand();
        print WRITER "Child Pid $$ ($stage) is sending this\n";
    } while (rand > 0.5);
    exit;
}

# initial set of children
for (my $i=0; $i<5; $i++) {
    if (fork() == 0) {
        child_process("LAUNCH");
    }
}

# parent
my ($rin,$rout) = ('');
vec($rin,fileno(READER),1) = 1;
while (1) {
     # non-blocking read on pipe
     my $read_avail = select($rout=$rin, undef, undef, 0.0);
     if ($read_avail < 0) {
         if (!$!{EINTR}) {
             warn "READ ERROR: $read_avail $!\n";
             last;
         }
     } elsif ($read_avail > 0) {
         chomp(my $line = <READER>);
         print "Read in Parent $$: '$line'\n";
     } else {
         print STDERR "No input ... do other stuff\n";
         # start some run-time child processes
         if (time-$^T > 5 && time-$^T < 10) {
             # launch a few more children in the middle of the program
             if (fork() == 0) {
                 child_process("RUN");
             }
         }
         sleep 1;
     }
     last if waitpid(-1,&WNOHANG) < 0;    # no more children are alive
}
close WRITER;  # now it is safe to do this ...

这篇关于perl:一位家长,许多孩子——家长中的单管阅读器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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