这些设置有什么区别?
$SIG{CHLD} = 'IGNORE'
$SIG{CHLD} = 'DEFAULT'
$SIG{CHLD} = ''
$SIG{CHLD} = undef
根据“UNIX环境中的高级编程,第2版”,图10.1 SIGCHLD的默认值为“ignore”。
如果“忽略”意味着“SIG_IGN”,那么任何孩子都不会成为僵尸,事实并非如此。
从那里开始并没有那么清楚:
如果该过程专门将其处置设置为SIG_IGN,则为子项 调用进程不会生成僵尸进程。注意 这与其默认操作(SIG_DFL)不同,后者来自图 10.1将被忽略。相反,在终止时,这些子进程的状态 被丢弃了。
我很难了解各种值(或未定义的非值)的影响。到目前为止,解决方案一直是轮换这些选择,直到我得到所需的行为,而我更确切地了解每个值如何定义信号的行为。
行为:子进程正在调用“system”或使用反引号来创建另一个子进程,并且信号通常会被错误的(父)处理程序捕获。设置本地处理程序可以工作,但如果我希望来自祖母的信号什么都不做,我不明白哪个值最合适。
有人可以照亮我吗?
更新 根据ikegami的反馈,我做了一些具体的测试。该行为至少部分是特定于平台的。
考虑以下片段:
$SIG{CHLD} = sub {
while( ( my $child = waitpid( -1, &WNOHANG ) ) > 0 ) {
print "SIGNAL CHLD $child\n";
}
};
my $pid = fork();
if( ! $pid ) {
system( 'echo Grandchild PID = $$' );
sleep 2;
exit;
}
print "Child PID = $pid\n";
sleep 5;
Solaris 10上的Perl 5.8.6将显示system()调用的PID的“SIGNAL CHLD”消息。做任何事情,即使像
那样微不足道孩子中的本地$ SIG {CHLD};
会压制这些消息。
在我尝试过的每一种味道上,收割者都看不到孩子。
答案 0 :(得分:12)
有两种方法可以避免创建僵尸进程:
$SIG{CHLD}='IGNORE'
wait
或waitpid
调用明确地抓住死去的孩子(这可以在SIGCHLD处理程序中完成,但不一定要这样做)设置$SIG{CHLD}='IGNORE'
在操作系统级别捕获SIGCHLD,清除子进程,甚至不用发信号通知您的Perl程序。
任何其他设置,包括'DEFAULT'
,undef
,""
,sub {}
,'some_function_name_that_doesnt_even_exist'
都会导致信号传递给Perl和孩子将不会自动获得。
通过使用wait
和waitpid
自行获取流程,您可以获得其他信息,例如子流程的退出状态,以及(或多或少)子流程的处理顺序完了。如果$SIG{CHLD}
设置为'IGNORE'
,则wait
和waitpid
始终返回-1并且不设置$?
。
SIGCHLD
,如果有的话,总是被传递给产生子进程的进程,所以我不认为你说来自孙子进程的SIGCHLD
是正确的。父进程中捕获了{child}进程中的system
调用。可能发生的事情是你的子进程从其父进程继承信号处理程序。
system
和反引号(在大多数系统上)将在完成时生成SIGCHLD
,并将使用命令的退出状态设置$?
值。但Perl本身会收获这些子流程,您将无法使用system
或wait
捕获waitpid
或反引号通话的流程ID。
答案 1 :(得分:10)
请参阅%SIG
。
$SIG{CHLD} = 'IGNORE';
会导致您的进程忽略SIGCHLD信号。
$SIG{CHLD} = 'DEFAULT';
会导致您的进程处理SIGCHLD信号,就像您没有使用$SIG{CHLD}
或等效信号一样。根据kill(1),我的系统上的进程默认忽略SIGCHLD
$SIG{CHLD} = '';
和$SIG{CHLD} = undef;
不是有效值。
至于收割,系统会在退出后立即自动获取其SIGCHLD处理程序明确设置为IGNORE
的父级子女。
$ perl -e'
my $pid = fork;
if (!$pid) { sleep(1); exit; }
sleep(2);
system "ps -o pid,stat,command $pid";
'
PID STAT COMMAND
14667 ZN+ [perl] <defunct>
$ perl -e'
$SIG{CHLD}="IGNORE";
my $pid = fork;
if (!$pid) { sleep(1); exit; }
sleep(2);
system "ps -o pid,stat,command $pid";
'
PID STAT COMMAND
$
答案 2 :(得分:2)
“忽略”有两种不同的含义,它们发生在两个不同的评估点。
第一个用途是关于是否传递信号。当子进程退出时,它通常由操作系统保存,并且CHLD信号被发送到其父进程。将$ SIG {CHLD}设置为'IGNORE'时,它会告诉系统不要生成信号并让子进程退出。父母没有机会获得有关子进程的信息,也没有僵尸的结果。
但是如果$ SIG {CHLD}不是'IGNORE',它意味着将信号传递给父进程,此时有自定义信号处理程序或默认信号处理程序,默认处理程序将在不同系统甚至同一操作系统的版本上有所不同。如果将信号传递给父进程(即处理程序未设置为'IGNORE'),book和signal(7)手册页将讨论默认情况下发生的情况。因此第二次使用忽略与动作采取交付信号有关。例如,SIGINT将导致您的进程终止,而SIGSTOP将导致您的进程“暂停”,尽管自定义信号处理程序会更改这些默认操作。
对于SIGCHLD信号,默认是“忽略”它,但在这个用法中,它只是意味着(父)进程在子进程等待时正常继续执行(即没有终止或中止父进程)。然后,您可以稍后等待()获取信息并避免僵尸。
答案 3 :(得分:1)
$ SIG {CHLD} ='IGNORE'
这将作为SIG_IGN传递给操作系统,根据操作系统文档,它会使子进程终止并变为僵尸(或将其退出代码报告给父进程)。
$ SIG {CHLD} ='默认'
$ SIG {CHLD} =''
$ SIG {CHLD} = undef
这些在OS级别都是相同的(它们将使用SIG_DFL调用signal())。但是,当$ SIG {CHLD}设置为'DEFAULT'时,某些perl包,尤其是AnyEvent :: child,将无效。