Linux 将术语信号发送到父进程的另一个线程中生成的子进程

Linux 将术语信号发送到父进程的另一个线程中生成的子进程,linux,multithreading,perl,signals,multiprocessing,Linux,Multithreading,Perl,Signals,Multiprocessing,我在Linux平台上使用Perl。首先,我创建了一个线程,并在这个新线程中分叉了一个子进程。当新线程中的父线程返回并加入主线程时,我想向创建的线程中生成的子进程发送术语信号,但信号处理程序不工作,子进程变成僵尸。这是我的密码: use strict; use warnings; use Thread 'async'; use POSIX; my $thrd = async { my $pid = fork(); if ($pid == 0) { $SIG{TER

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

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";
    }
}

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

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

(消息“child$$exits”是在child的1中输出的,因此它在屏幕上不可见,对吗?)


编辑:我刚刚试过你的例子,我想我明白了:你在子进程中执行一个fork,并检查pid是否为0(这是父异步进程)。您可以检查一下!=0.

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

除非您等待,否则所有子进程都将变成僵尸。Put
waitpid($pid,0)
kill()之后。除非您在打印输出中看到子进程:循环5中的
,否则kill和信号处理程序工作正常

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

编辑:

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

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

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

这将解决您的问题

孩子的1实际上是标准输出,通常它会打印出消息。我认为不同的平台和不同的线程模型可能会有不同的行为,非常好奇里面发生了什么…谢谢,硬编码文件只是数据库的简化版本,所以这个程序是我的web应用程序的一个简单模型,它使用数据库来存储PID。对于僵尸部分,很抱歉这是我的错,我忘了添加收割器功能,但在我的web应用程序中,我确实安装了CHLD信号处理程序。我只是想知道为什么
打印“child$$exits!\n”
不起作用,为什么孩子没有向家长发送CHLD信号。我通过在程序中添加一个收割者来编辑这个问题。但反正也没打电话给我我不太明白。。。这不是一个无休止的递归吗
sigforwarder
捕获一个
TERM
信号,并将一个
TERM
信号重新发送给child,然后再次调用
sigforwarder
。是的,它看起来像这样。如上所述,我不太确定您看到的不是perl中的bug。perl似乎没有意识到子进程中只有一个线程,并且似乎表现为有两个线程。sigforwarder只允许“子线程”获取信号。perl将仅在接收到信号时运行进程信号处理程序,并在转发后运行线程sig处理程序,因此不存在递归。请注意,您可以通过在主线程中分叉来解决问题,而不是在子线程中分叉好的,谢谢,我将尝试为我的程序找到解决方法,而不是在子线程上分叉。