2

我在 Linux 平台上并使用 Perl。首先我创建了一个线程,并在这个新线程中派生了一个子进程。当新线程中的父级返回并加入主线程时,我想向创建的线程中生成的子进程发送 TERM 信号,但是信号处理程序不起作用,子进程变成了僵尸。这是我的代码:

use strict;
use warnings;
use Thread 'async';
use POSIX;

my $thrd = async {
    my $pid = fork();
    if ($pid == 0) {
        $SIG{TERM} = \&child_exit;
        `echo $$ > 1`;
        for (1..5) {
            print "in child process: cycle $_\n";
            sleep 2;
        }
        exit(0);
    }
    else {
        $SIG{CHLD} = \&reaper;
    }
};

$thrd->detach();
sleep 4;
my $cpid = `cat 1`;
kill "TERM", $cpid;
while (1) {}

sub child_exit {
    print "child $$ exits!\n";
    exit(0);
}

sub reaper {
    my $pid;
    while (($pid = waitpid(-1, &WNOHANG)) > 0) {
        print "reaping child process $pid\n";
    }
}

关于如何在这种情况下成功安全地发送信号有什么建议吗?

4

2 回答 2

2

你为什么说 SIGTERM 处理程序不起作用?因为孩子变成了僵尸?

除非您等待它们,否则所有子进程都会变成僵尸。放在waitpid($pid, 0);后面kill()。除非您in child process: cycle 5在打印输出中看到,否则 kill 和信号处理程序工作正常。

请注意,使用硬编码文件在分叉进程和主进程之间进行通信是非常不稳定的。我建议你使用管道。

编辑:

Wrt 你的 sig 处理程序没有被调用,我认为这是一个 perl 错误。perl 只向主线程发送信号。当你 fork() 时,你的线程成为主线程,但我认为 perl 没有意识到这一点。您可以通过将信号重新转发给自己来解决此问题。

在创建线程之前,只需添加:

sub sigforwarder {
    threads->self()->kill(shift);
}
$SIG{TERM} = \&sigforwarder;

应该可以解决您的问题

于 2013-05-16T14:20:50.213 回答
0

我认为问题是 child_exit 没有在父线程上执行任何退出。它只是退出了孩子。我不确切知道 perl 中发生了什么(只是偶然发现了 c 中的 fork/exec 构造),但我会尝试在父进程中捕获 SIG_CHILD 以检测其终止。

(消息“child $$ exits”在孩子的1中输出,所以它不会在屏幕上可见,对吧?)

编辑:我刚刚尝试了您的示例,我想我明白了:您正在子进程中执行分叉并检查 pid 是否为 0(这是父异步进程)。您可能只检查!= 0。

于 2013-05-16T11:26:31.943 回答