Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Perl 信号干扰管道通信的方式有哪些?_Perl_Pipe_Ipc - Fatal编程技术网

Perl 信号干扰管道通信的方式有哪些?

Perl 信号干扰管道通信的方式有哪些?,perl,pipe,ipc,Perl,Pipe,Ipc,我对信号一无所知,对管道也知之甚少 从对 似乎信号可能会干扰父进程和子进程之间的管道通信 有人告诉我,如果你使用 和 , 然后是子进程的退出 可能会以某种方式扰乱IO::Select::can_read的行为, 特别是如果有多个子进程 请描述使用管道时如何解释信号?下面的代码是一个不考虑信号的示例 use warnings; use strict; use feature 'say'; use Time::HiRes qw(sleep); use IO::Select; my $sel =

我对信号一无所知,对管道也知之甚少

从对 似乎信号可能会干扰父进程和子进程之间的管道通信

有人告诉我,如果你使用 和 , 然后是子进程的退出 可能会以某种方式扰乱IO::Select::can_read的行为, 特别是如果有多个子进程

请描述使用管道时如何解释信号?下面的代码是一个不考虑信号的示例

use warnings;
use strict;
use feature 'say';

use Time::HiRes qw(sleep);
use IO::Select; 

my $sel = IO::Select->new;

pipe my $rd, my $wr;
$sel->add($rd); 

my $pid = fork // die "Can't fork: $!";  #/

if ( $pid == 0 ) {     # Child code

    close $rd; 
    $wr->autoflush;

    for ( 1..4 ) {

        sleep 1;
        say "\tsending data";
        say $wr 'a' x ( 120 * 1024 );
    }

    say "\tClosing writer and exiting";
    close $wr;

    exit; 
}

# Parent code
close $wr;    
say "Forked and will read from $pid";

my @recd;

READ:
while ( 1 ) {

    if ( my @ready = $sel->can_read(0) ) {  # beware of signals

        foreach my $handle (@ready) {

            my $buff;
            my $rv = sysread $handle, $buff, ( 64 * 1024 );
            warn "Error reading: $!" if not defined $rv;

            if ( defined $buff and $rv != 0 ) {
                say "Got ", length $buff, " characters";
                push @recd, length $buff; 
            }

            last READ if $rv == 0;
        }
    }
    else {
        say "Doing else ... ";
        sleep 0.5; 
    }
}   
close $rd;

my $gone = waitpid $pid, 0;

say "Reaped pid $gone";
say "Have data: @recd"

信号还可能中断I/O功能,导致随后出现故障,
$设置为
EINTR
。因此,您应该检查该错误,并在错误发生时重试

不这样做是很难找到的bug的常见来源。

两件事

  • 在读卡器关闭后写入管道(例如,可能是因为另一端的进程退出)会导致SIGPPIPE。您可以忽略此信号(
    $SIG{PIPE}='ignore';
    ),以使写入返回错误
    eppe

    在您的情况下,如果您希望处理该错误而不是让程序被终止,只需添加

    $SIG{PIPE} = 'IGNORE';
    
  • 如果定义了任何信号处理程序(例如,使用
    $SIG{…}=sub{…};
    ,而不是
    $SIG{…}='IGNORE';
    $SIG{…}='DEFAULT';
    ),长时间运行的系统调用(例如,从文件句柄读取)可能会被信号中断。如果发生这种情况,它们将返回错误
    EINTR
    ,给信号处理程序一个运行的机会。在Perl中,除了重新启动失败的系统调用外,无需执行任何操作

    在您的情况下,没有定义信号处理程序,因此这不会影响您


  • 顺便说一下,即使已知
    $rv
    未定义,也要检查
    $rv==0
    ,并将数据长度放在
    @recd
    中,而不是放在数据本身中。事实上,在那里使用数组没有多大意义。替换

    my @recd;
    
    ...
    
    my $rv = sysread $handle, $buff, ( 64 * 1024 );
    warn "Error reading: $!" if not defined $rv;
    
    if ( defined $buff and $rv != 0 ) {
        say "Got ", length $buff, " characters";
        push @recd, length $buff; 
    }
    
    last READ if $rv == 0;
    
    ...
    
    say "Have data: @recd"
    


    再说一次,你有没有想过用管道来达到这个目的?使用用于进程间通信的文件,您将在容量、死锁、信号和可移植性方面减少麻烦。和调试(在程序结束时,您可以检查文件,看看它是否包含您期望的内容)。我尝试使用管道,因为我似乎真的应该学习它们如何工作,才能成为一名优秀的工程师。但相比之下,它确实显得过于复杂。我觉得我在良好的设置方面取得了进展,但我还没有达到一个舒适的程度,我认为它应该足够可靠。我相信管道也会更快,但是的,也许我会放弃这一努力:(如果您对IPC总体不满意,那么切换到使用文件将不会有多大帮助:会出现许多相同的问题,最后您必须意识到在共享资源时并行运行进程的后果。我想您已经阅读并吸收了?谢谢,这提供了我所缺少的更多上下文。我现在明白了中断的发生是为了让我定义的信号处理程序能够继续。有一件事我不明白:写入如何返回
    EPIPE
    ?您的意思是写入条件本身的返回值将是一个字符串EPIPE吗?这样会更好吗?让我们来看看。@zdim,因为您正在更正您的帖子…我想我使用
    foreach my$handle(@ready)循环句柄是错误的
    当您知道只有一个句柄时。特别是,因为您正在调用命令
    上次读取;
    当您看到一个关闭的句柄时,代码甚至不能与多个句柄一起工作。@ikegami,有一件事可以在文章中详细说明:如果遇到警告,我们为什么不尝试重新读取句柄($rv未定义)。是否存在可恢复的错误?可能您已向zdim解释了这一点,但注释已被删除。
    my $buf = '';
    
    ...
    
    my $received = sysread($handle, $buf, 64 * 1024, length($buf));
    warn "Error reading: $!" if !defined($received);
    last if !$received;
    
    say "Got $received characters";
    
    ...
    
    say "Have data: $buf"