信号干扰管道通信的方式有哪些? [英] What are the ways that signals can interfere with pipe communication?

查看:117
本文介绍了信号干扰管道通信的方式有哪些?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对信号一无所知,对管道一无所知.

I don't know anything about signals, and only a little about pipes.

来自的评论 zdim的在此处回答 似乎信号可能会干扰父子进程之间的管道通信.

From the comments on zdim's answer here it seems that signals may interfere with pipe communication between parent and child processes.

有人告诉我,如果您使用的是 IO::Select sysread , 然后退出子进程 可能以某种方式弄乱IO::Select::can_read的行为, 尤其是在有多个子进程的情况下.

I was told that, if you're using IO::Select and sysread, then the exit of a child process could somehow mess up the behavior of IO::Select::can_read, especially if there are multiple child processes.

请描述在使用管道时如何考虑信号?以下代码是一个示例,其中未考虑信号.

Please describe how to account for signals when using pipes? The below code is an example where signals are not accounted for.

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"

推荐答案

两件事.

  1. 在关闭阅读器后写到管道(例如,可能是因为另一端的进程已退出)导致生成SIGPIPE.您可以忽略此信号($SIG{PIPE} = 'IGNORE';),以使写入返回错误EPIPE.

  1. Writing to a pipe after the reader was closed (e.g. perhaps because the process on the other end exited) leads to a SIGPIPE. You can ignore this signal ($SIG{PIPE} = 'IGNORE';) in order to have the write to return error EPIPE instead.

在您的情况下,如果您想处理该错误而不是杀死程序,只需添加

In your case, if you wanted to handle that error instead of having your program killed, simply add

$SIG{PIPE} = 'IGNORE';

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

  • If you have any signal handler defined (e.g. using $SIG{...} = sub { ... };, but not $SIG{...} = 'IGNORE'; or $SIG{...} = 'DEFAULT';), long-running system calls (e.g. reading from a file handle) can be interrupted by a signal. If this happens, they will return with error EINTR to give the signal handler a chance to run. In Perl, you don't have to do anything but restart the system call that failed.

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

    In your case, you have no signal handlers defined, so this doesn't affect you.


    顺便说一句,即使已知$rv是不确定的,也要检查$rv == 0,然后将数据的长度放在@recd中,而不是数据本身.实际上,在那里根本不使用数组是没有任何意义的.替换


    By the way, you check $rv == 0 even when $rv is known to be undefined, and you place the length of the data in @recd instead of the data itself. In fact, it doesn't make much sense to use an array there at all. Replace

    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"
    

    使用

    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"
    

    这篇关于信号干扰管道通信的方式有哪些?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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