Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/visual-studio-2012/2.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 处理简单父子IPC的信号和子出口值组合?_Perl - Fatal编程技术网

Perl 处理简单父子IPC的信号和子出口值组合?

Perl 处理简单父子IPC的信号和子出口值组合?,perl,Perl,我试图找出正确的方法来处理一个简单的父子进程间通信(IPC)案例。子对象通过子对象的STDOUT句柄向父对象发送消息。父代不会向子代发送任何消息(如果子代死亡,则SIGPIPE除外)。此外,子级和父级都需要处理来自终端用户的SIGINT信号。父进程的主要困难是,当子进程死于SIGINT或SIGPIPE时,要正确获取子进程的退出状态 parent.pl: #! /usr/bin/env perl use feature qw(say); use strict; use warnings; my

我试图找出正确的方法来处理一个简单的父子进程间通信(IPC)案例。子对象通过子对象的
STDOUT
句柄向父对象发送消息。父代不会向子代发送任何消息(如果子代死亡,则
SIGPIPE
除外)。此外,子级和父级都需要处理来自终端用户的
SIGINT
信号。父进程的主要困难是,当子进程死于
SIGINT
SIGPIPE
时,要正确获取子进程的退出状态

parent.pl

#! /usr/bin/env perl

use feature qw(say);
use strict;
use warnings;

my $child_pid = open ( my $fh, '-|', 'child.pl' ) or die "Could not start child: $!";

$SIG{INT} = sub {
    $SIG{CHLD}="IGNORE";
    die "Caught SIGINT"
};

my $child_error;

$SIG{CHLD} = sub {
    $SIG{INT}="IGNORE";
    waitpid $child_pid, 0;
    $child_error = $?;
    die "Caught SIGCHLD: Child exited.."
};

eval {
    while (1) {
        msg( "sleeping(1).." );
        sleep 1;
        #internal_failure();
        msg( "waiting for child input.." );
        my $line = <$fh>;
        if ( defined $line ) {
            chomp $line;
            msg( "got line: '$line'" );
        }
        else {
            die "Could not read child pipe.";
        }
        msg( "sleeping(2).." );
        sleep 2;
    }
};

if ( $@ ) {
    chomp $@;
    msg( "interrupted: '$@'" );
}

my $close_ok = close $fh; # close() will implicitly call waitpid()
if ( !$close_ok ) {
    msg( "Closing child pipe failed: $!" );
    if ( !defined $child_error ) {
        waitpid $child_pid, 0;
    }
}
if ( !defined $child_error ) {
    $child_error = $?;
}
my $child_signal = $child_error & 0x7F;
if ( $child_signal ) {
    msg( "Child died from signal: $child_signal" );
}
else {
    msg( "Child exited with return value: " . ($child_error >> 8) );
}
exit;

sub msg { say "Parent: " . $_[0]  }

sub internal_failure {
    $SIG{CHLD}="IGNORE";
    $SIG{INT}="IGNORE";
    die "internal failure";
}
#! /usr/bin/env perl

use feature qw(say);
use strict;
use warnings;

$SIG{PIPE} = sub {
    $SIG{INT}="IGNORE";
    die "Caught SIGPIPE: Parent died.";
};

$SIG{INT} = sub {
    $SIG{PIPE}="IGNORE";
    die "Caught SIGINT\n";  # For some reason a newline is needed here !?
};

#local $SIG{INT} = "IGNORE";

STDOUT->autoflush(1); # make parent see my messages immediately
msg( "running.." );
eval {
    sleep 2;
    say "Hello"; # should trigger SIGPIPE signal if parent is dead
    sleep 1;
};
if ( $@ ) {
    chomp $@;
    msg( "interrupted: '$@'" );
    exit 2;
}

msg( "exits" );
exit 1;
从命令行运行
parent.pl
的正常输出为:

Parent: sleeping(1)..
Child: running..
Parent: waiting for child input..
Parent: got line: 'Hello'
Parent: sleeping(2)..
Child: exits
Parent: interrupted: 'Caught SIGCHLD: Child exited.. at ./parent.pl line 20, <$fh> line 1.'
Parent: Closing child pipe failed: No child processes
Parent: Child exited with return value: 1
避免在以后接收到
SIGCHLD
。例如,如果我没有禁用子信号,它可能会到达父对象中的清理部分(在
eval
块之后),并使父对象在完成清理之前死亡

问题2:处理信号

如果在启动父级后按CTRL-C,输出通常如下所示:

Parent: sleeping(1)..
Child: running..
Parent: waiting for child input..
^CChild: interrupted: 'Caught SIGINT'
Parent: interrupted: 'Caught SIGINT at ./parent.pl line 11.'
Parent: Closing child pipe failed: No child processes
Parent: Child died from signal: 127
这里的问题是孩子的退出状态。它应该是2,但它被信号127杀死。这里的信号127是什么意思

问题3:母公司因内部故障死亡

如果我取消对该行的注释

#internal_failure();
parent.pl
中,输出为:

Parent: sleeping(1)..
Child: running..
Parent: interrupted: 'internal failure at ./parent.pl line 71.'
Child: interrupted: 'Caught SIGPIPE: Parent died. at ./child.pl line 9.'
Parent: Closing child pipe failed: No child processes
Parent: Child died from signal: 127

除了子进程的退出状态外,这似乎工作得很好。它应该是2,而是被信号127杀死。

您将子项设置为(
$SIG{CHLD}=“IGNORE”
),然后您调用了
waitpid
,不是一次,而是两次

waitpid
的后续调用将
$?
设置为
-1
(发出错误信号,但您将其误解为“被信号杀死”),并且
$
无子进程

修正:

$ diff -u ./parent.pl{~,}
--- ./parent.pl~        2016-09-19 19:28:39.778244653 -0700
+++ ./parent.pl 2016-09-19 19:28:10.698227008 -0700
@@ -7,16 +7,12 @@
 my $child_pid = open ( my $fh, '-|', 'child.pl' ) or die "Could not start child: $!";

 $SIG{INT} = sub {
-    $SIG{CHLD}="IGNORE";
+    $SIG{CHLD}="DEFAULT";
     die "Caught SIGINT"
 };

-my $child_error;
-
 $SIG{CHLD} = sub {
     $SIG{INT}="IGNORE";
-    waitpid $child_pid, 0;
-    $child_error = $?;
     die "Caught SIGCHLD: Child exited.."
 };

@@ -44,29 +40,19 @@
     msg( "interrupted: '$@'" );
 }

-my $close_ok = close $fh; # close() will implicitly call waitpid()
-if ( !$close_ok ) {
-    msg( "Closing child pipe failed: $!" );
-    if ( !defined $child_error ) {
-        waitpid $child_pid, 0;
-    }
-}
-if ( !defined $child_error ) {
-    $child_error = $?;
-}
-my $child_signal = $child_error & 0x7F;
-if ( $child_signal ) {
-    msg( "Child died from signal: $child_signal" );
-}
-else {
-    msg( "Child exited with return value: " . ($child_error >> 8) );
-}
+close $fh; # close() will implicitly call waitpid()
+
+if    ( $? == -1  ) { msg( "Closing child pipe failed: $!" ); }
+elsif ( $? & 0x7F ) { msg( "Child died from signal ".( $? & 0x7F ) ); }
+elsif ( $? >> 8   ) { msg( "Child exited with error ".( $? >> 8 ) ); }
+else                { msg( "Child executed successfully" ); }
+
 exit;

 sub msg { say "Parent: " . $_[0]  }

 sub internal_failure {
-    $SIG{CHLD}="IGNORE";
+    $SIG{CHLD}="DEFAULT";
     $SIG{INT}="IGNORE";
     die "internal failure";
 }
修复了父.pl

#! /usr/bin/env perl

use feature qw(say);
use strict;
use warnings;

my $child_pid = open ( my $fh, '-|', 'child.pl' ) or die "Could not start child: $!";

$SIG{INT} = sub {
    $SIG{CHLD}="DEFAULT";
    die "Caught SIGINT"
};

$SIG{CHLD} = sub {
    $SIG{INT}="IGNORE";
    die "Caught SIGCHLD: Child exited.."
};

eval {
    while (1) {
        msg( "sleeping(1).." );
        sleep 1;
        #internal_failure();
        msg( "waiting for child input.." );
        my $line = <$fh>;
        if ( defined $line ) {
            chomp $line;
            msg( "got line: '$line'" );
        }
        else {
            die "Could not read child pipe.";
        }
        msg( "sleeping(2).." );
        sleep 2;
    }
};

if ( $@ ) {
    chomp $@;
    msg( "interrupted: '$@'" );
}

close $fh; # close() will implicitly call waitpid()

if    ( $? == -1  ) { msg( "Closing child pipe failed: $!" ); }
elsif ( $? & 0x7F ) { msg( "Child died from signal ".( $? & 0x7F ) ); }
elsif ( $? >> 8   ) { msg( "Child exited with error ".( $? >> 8 ) ); }
else                { msg( "Child executed successfully" ); }

exit;

sub msg { say "Parent: " . $_[0]  }

sub internal_failure {
    $SIG{CHLD}="DEFAULT";
    $SIG{INT}="IGNORE";
    die "internal failure";
}
#/usr/bin/env perl
使用特征qw(例如);
严格使用;
使用警告;
我的$child_pid=open(我的$fh、-|'、'child.pl')或die“无法启动child:$!”;
$SIG{INT}=sub{
$SIG{CHLD}=“默认”;
死亡“抓住信号”
};
$SIG{CHLD}=sub{
$SIG{INT}=“忽略”;
死亡“捕获信号:孩子退出…”
};
评估{
而(1){
味精(“睡眠(1)…);
睡眠1;
#内部故障();
msg(“等待子输入…”);
我的$line=;
如果(定义的$行){
chomp$行;
msg(“获取行:“$line”);
}
否则{
“无法读取子管道。”;
}
味精(“睡眠(2)…);
睡眠2;
}
};
如果($@){
chomp$@;
msg(“中断:“$@”);
}
收盘价$fh;#close()将隐式调用waitpid()
如果($?==-1){msg(“关闭子管道失败:$!”);}
elsif($?&0x7F){msg(“孩子死于信号”。($?&0x7F));}
elsif($?>>8){msg(“子项因错误退出”。($?>>8));}
else{msg(“成功执行子项”);}
出口
子消息{say“Parent:.$\u0]}
次内部故障{
$SIG{CHLD}=“默认”;
$SIG{INT}=“忽略”;
模具“内部失效”;
}

信号处理仍然很混乱,但我想避免更改与修复无关的代码。

$child\u error
可能是由于在信号处理程序之外使用
waitpid
而导致的
-1
。(
-1&0x7F==0x7F==127
)。关闭句柄也会调用
waitpid
。你弄得一团糟。选择要调用waitpid的位置,并消除另外两个到处都是!哇!为什么?注意:一般来说,您需要在SIGCHLD处理程序中有一个循环,因为可能有多个孩子死亡。@ikegami感谢您的评论!关于SigChLD的循环:我在考虑这个问题,但是因为我只考虑了一个孩子,我认为这不是必要的,就像我说的,“一般来说”。这里,就像你说的,没问题。谢谢你的清理,看起来不错!我看到从子信号处理程序内部删除
waitpid
似乎是可行的,但是根据:“如果您为SIGCHLD安装了信号处理程序,那么$?的值在该处理程序外部通常是错误的。”。那么如何从文档中解释这个语句呢?也就是说$?如果在处理程序中设置,但在处理程序外部检查,则可能不正确。但是在本例中,您在处理程序外部调用waitpid,因此当然可以检查$?这里。@zdim“当我交换它们时,它表现得更好。”我不确定我是否理解。这里的交换是什么意思?
eval
中的
local
处理程序?设置一个标志而不是死亡?@HåkonHægland我为我对涉及其他信号的处理程序的无知评论道歉——你说得很好,我没看到。我确实认为这不必要地使事情复杂化,但这些评论是不恰当的,因为这确实是有意的。我把它们拿走了。很抱歉。
#! /usr/bin/env perl

use feature qw(say);
use strict;
use warnings;

my $child_pid = open ( my $fh, '-|', 'child.pl' ) or die "Could not start child: $!";

$SIG{INT} = sub {
    $SIG{CHLD}="DEFAULT";
    die "Caught SIGINT"
};

$SIG{CHLD} = sub {
    $SIG{INT}="IGNORE";
    die "Caught SIGCHLD: Child exited.."
};

eval {
    while (1) {
        msg( "sleeping(1).." );
        sleep 1;
        #internal_failure();
        msg( "waiting for child input.." );
        my $line = <$fh>;
        if ( defined $line ) {
            chomp $line;
            msg( "got line: '$line'" );
        }
        else {
            die "Could not read child pipe.";
        }
        msg( "sleeping(2).." );
        sleep 2;
    }
};

if ( $@ ) {
    chomp $@;
    msg( "interrupted: '$@'" );
}

close $fh; # close() will implicitly call waitpid()

if    ( $? == -1  ) { msg( "Closing child pipe failed: $!" ); }
elsif ( $? & 0x7F ) { msg( "Child died from signal ".( $? & 0x7F ) ); }
elsif ( $? >> 8   ) { msg( "Child exited with error ".( $? >> 8 ) ); }
else                { msg( "Child executed successfully" ); }

exit;

sub msg { say "Parent: " . $_[0]  }

sub internal_failure {
    $SIG{CHLD}="DEFAULT";
    $SIG{INT}="IGNORE";
    die "internal failure";
}