Perl 信号干扰管道通信的方式有哪些?
我对信号一无所知,对管道也知之甚少 从对 似乎信号可能会干扰父进程和子进程之间的管道通信 有人告诉我,如果你使用 和 , 然后是子进程的退出 可能会以某种方式扰乱IO::Select::can_read的行为, 特别是如果有多个子进程 请描述使用管道时如何解释信号?下面的代码是一个不考虑信号的示例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 =
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"