各种 $SIG{CHLD} 值之间有什么区别?
这些设置有什么区别?
$SIG{CHLD} = 'IGNORE'
$SIG{CHLD} = 'DEFAULT'
$SIG{CHLD} = ''
$SIG{CHLD} = undef
根据《UNIX环境中的高级编程,第2版》,图10.1中SIGCHLD的默认值是“忽略”。
如果“忽略”意味着“SIG_IGN”,那么没有孩子会成为僵尸,但事实并非如此。
从那里并没有变得更清楚:
如果进程专门将其处置设置为 SIG_IGN,则子进程 调用进程的进程不会生成僵尸进程。注意 这与它的默认操作(SIG_DFL)不同,从图 10.1 被忽略。相反,在终止时,这些子进程的状态 被丢弃。
我很难理解各种值(或未定义的非值)的影响。到目前为止,解决方案是轮流选择这些选择,直到获得所需的行为,并且我宁愿确切地了解每个值如何定义信号的行为。
行为:子进程正在调用“系统”或使用反引号创建另一个子进程,并且该信号通常会被错误的(父)处理程序捕获。设置本地处理程序可以工作,但如果我希望来自孙子的信号不执行任何操作,我不知道哪个值最合适。
有人可以照亮我吗?
更新: 根据池上的反馈,我做了一些具体的测试。该行为至少部分是特定于平台的。
考虑以下片段:
$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};
孩子会抑制这些信息。
在我尝试过的所有其他口味中,收割者从未见过孩子。
What is the difference between these settings?
$SIG{CHLD} = 'IGNORE'
$SIG{CHLD} = 'DEFAULT'
$SIG{CHLD} = ''
$SIG{CHLD} = undef
According to "Advanced Programming in the UNIX Environment, 2nd edition", figure 10.1 the default value of SIGCHLD is "ignore."
If "ignore" meant "SIG_IGN", then no child would ever be a zombie, and that's not the case.
It doesn't get much more clear from there:
If the process specifically sets its disposition to SIG_IGN, children
of the calling process will not generate zombie processes. Note that
this is different from its default action (SIG_DFL), which from Figure
10.1 is to be ignored. Instead, on termination, the status of these child processes
is discarded.
I'm having a hard time groking what the impact of the various values (or undefined non-value) are. So far, the solution has been to rotate through those choices until I get the desired behavior, and I'd rather understand exactly how each value defines the behavior of the signal.
The behavior: a child process is calling "system" or using backticks which create another child, and the signal would normally be caught by the wrong (parent) handler. Setting a local handler can work, but I don't understand which value is most appropriate if I want the signal from the grand-child to do nothing.
Could someone please illuminate me?
UPDATE:
Based on ikegami's feedback, I did some specific testing. The behavior is, at least partially, platform specific.
Consider the following fragment:
$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;
Perl 5.8.6 on Solaris 10 will display "SIGNAL CHLD" messages for the PID of the system() call. Doing anything, even as trivial as
local $SIG{CHLD};
in the child will suppress those messages.
On every other flavor I tried, the reaper never sees the child.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
有两种方法可以避免创建僵尸进程:
$SIG{CHLD}='IGNORE'
wait
或waitpid
显式获取死亡子进程code> 调用(这可以在 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
是不正确的(来自子进程中的系统
调用)在父进程中被捕获。可能发生的情况是您的子进程从其父进程继承了信号处理程序。system
和反引号(在大多数系统上)将在完成时生成SIGCHLD
,并将使用命令的退出状态设置$?
值。但是 Perl 会自己获取这些子进程,并且您将无法捕获system
的进程 ID 或使用wait
或waitpid
进行反引号调用>。There are two ways to avoid creating zombie processes:
$SIG{CHLD}='IGNORE'
wait
orwaitpid
calls (this could be done inside a SIGCHLD handler, but it need not be)Setting
$SIG{CHLD}='IGNORE'
traps the SIGCHLD at the operating system level, cleaning up the child process without even signalling your Perl program.Any other setting, including
'DEFAULT'
,undef
,""
,sub {}
,'some_function_name_that_doesnt_even_exist'
will cause the signal to be delivered to Perl, and the child will not be reaped automatically.By reaping the process yourself with
wait
andwaitpid
, you can get additional information like the exit status of the child process, and (more-or-less) the order in which the child processes finished. If$SIG{CHLD}
is set to'IGNORE'
,wait
andwaitpid
always return -1 and don't set$?
.The
SIGCHLD
, if any, is always delivered to the process that spawned the child process, so I don't think you are correct to say that aSIGCHLD
from a grandchild process (from asystem
call in a child process) is caught in the parent process. Probably what is going on is that your child process inherits the signal handler from its parent process.system
and backticks will (on most systems) generate aSIGCHLD
on completion and will set the$?
value with the command's exit status. But Perl will reap these subprocesses itself, and you won't be able to capture the process id of asystem
or backticks call withwait
orwaitpid
.请参阅
%SIG
。$SIG{CHLD} = 'IGNORE';
使您的进程忽略 SIGCHLD 信号。$SIG{CHLD} = 'DEFAULT';
使您的进程处理 SIGCHLD 信号,因为它不会让您弄乱$SIG{CHLD}
或同等信号。根据kill(1),我的系统上的进程默认忽略SIGCHLD$SIG{CHLD} = '';
和$SIG{CHLD} = undef;
不是有效值。至于收割,如果父级的 SIGCHLD 处理程序显式设置为 IGNORE,那么一旦退出,系统就会自动收割其子级。
See
%SIG
.$SIG{CHLD} = 'IGNORE';
causes your process to ignore SIGCHLD signals.$SIG{CHLD} = 'DEFAULT';
causes your process to treat SIGCHLD signals as it would had you not messed with$SIG{CHLD}
or equivalent. According to kill(1), a process on my system ignores SIGCHLD by default$SIG{CHLD} = '';
and$SIG{CHLD} = undef;
are not valid values.As for reaping, children of a parent whose SIGCHLD handler is explicitely set to
IGNORE
will be reaped automatically by the system as soon as it exits.“忽略”有两种不同的含义,它们发生在两个不同的评估点。
第一个用途涉及是否传递信号。当子进程退出时,它通常由操作系统保留,并向其父进程发送 CHLD 信号。当将 $SIG{CHLD} 设置为“IGNORE”时,它告诉系统根本不生成信号,而只是让子进程退出。父进程没有机会获取有关子进程的信息,因此不会产生僵尸进程。
但如果$SIG{CHLD}不是'IGNORE',则表示将信号传递给父进程,此时要么有自定义信号处理程序,要么有默认信号处理程序,并且默认处理程序会根据不同的情况而有所不同。系统甚至同一操作系统的不同版本。本书和 signal(7) 手册页讨论了如果将信号传递到父进程(即处理程序未设置为“IGNORE”),默认情况下会发生什么情况。因此,忽略的第二个用途与对传递的信号采取的操作有关。例如,SIGINT 将导致您的进程终止,而 SIGSTOP 将导致您的进程“暂停”,尽管自定义信号处理程序会更改这些默认操作。
对于SIGCHLD信号,默认是“忽略”它,但在这个用法中,它仅意味着(父)进程在子进程等待时继续正常执行(即不终止或中止父进程)过程)。然后您可以稍后对其进行 wait() 以获取其信息并避免僵尸。
There are two different meaning for "ignore", and they are occurring at two different points of evaluation.
The first use concerns whether to deliver the signal at all. When a child processes exits, it usually is held by the operating system and a CHLD signal is sent to its parent. When setting $SIG{CHLD} to 'IGNORE', it tells the system to not generate a signal at all and just let the child process exit. The parent has no opportunity to get information on the child process, and no zombies result.
But if $SIG{CHLD} is anything other than 'IGNORE', it means to deliver the signal to the parent process, at which point there is either a custom signal handler or a default signal handler, and the default handler will vary on different systems or even versions of the same operating system. The book and signal(7) man page talk about what happens by default if a signal is delivered to the parent process (i.e. handler is not set to 'IGNORE'). So the second use of ignore is related to which action to take for a delivered signal. For example SIGINT will cause your process to be terminated, and SIGSTOP will cause your process to "pause", although custom signal handlers change these default actions.
For the SIGCHLD signal, the default is to "ignore" it, but in this usage it just means the (parent) process just continues executing normally while the child process waits (i.e. no termination or aborting of parent process). You can then wait() on it later to get it's information and avoid a zombie.
这会作为 SIG_IGN 传递给操作系统,根据操作系统文档,这会使子进程终止而不会成为僵尸进程(或向父进程报告其退出代码)。
这些在操作系统级别都是相同的(它们将使用 SIG_DFL 调用 signal())。然而,当 $SIG{CHLD} 设置为“DEFAULT”时,某些 Perl 软件包(尤其是 AnyEvent::child)将无法工作。
This is passed to the OS as SIG_IGN, which according to the OS docs, makes the child processes terminate without becoming zombies (or reporting their exit code to the parent).
These are all the same at the OS level (they will call signal() with SIG_DFL). However some perl packages, notably AnyEvent::child, will not work when $SIG{CHLD} is set to 'DEFAULT'.