Perl杀孩子的过程也退出了父母?

时间:2015-10-24 18:04:02

标签: perl process fork

我在PERL中编写仿真存根来测试另一个程序。下面,代码运行一个循环来检查命令(initialize,exit,start_trace,stop_trace)。当" start_trace"读取命令,它会分叉一个只是每秒吐出数字的进程。我想使用" stop_trace"杀死孩子,但也杀死了父母。我错过了什么?

use warnings;
use strict;

my $pid = undef;

$| = 1;

$SIG{TERM} = sub { 
    if ($pid == 0) {
        print "Parent, not terminating\n";
    } else {
        print "Child ($pid) terminating\n"; 
        exit(1);
    }
};


print "entering loop\n";
while (1) {
    while (<>) {
        my ($command, @args) = split();
        if ($command eq "exit") {
            exit 1;
        }
        elsif ($command eq "initialize") {
            print "s: ok\n";
        }
        elsif ($command eq "start_trace") {
            if (defined $pid) {
                print "child already running\n";
            } else {
                $pid = fork();
                if ($pid == -1) {
                    print "failed to fork\n";
                    exit 1;
                }
                elsif ($pid == 0) {
                    print "Parent\n";
                }
                else {
                    my $timestamp = 0;
                    while (1) {
                        for (my $i = 0; $i < 12; ++$i) {
                            printf "%.3f %.0f %.2f %.1f\n", 
                                ++$timestamp,
                                0,
                                0,
                                100 * rand()
                            ;
                        }
                        sleep(1);
                    }
                }
            }
        }
        elsif ($command eq "stop_trace") {
            kill "TERM", $pid;
            #waitpid($pid, 0);
            $pid = undef;
        }
        else {
            printf "s: unknown command $command\n";
        }
    }
}

输出(不是stdin和stdout都混合在一起,但我打字&#34; stop_trace&#34;)

stop85.000 0 0.00 66.6
86.000 0 0.00 43.3
87.000 0 0.00 82.3
88.000 0 0.00 62.8
89.000 0 0.00 43.5
90.000 0 0.00 50.0
91.000 0 0.00 8.8
92.000 0 0.00 89.3
93.000 0 0.00 61.4
94.000 0 0.00 92.4
95.000 0 0.00 46.6
96.000 0 0.00 53.9
_trace
Child (26644) terminating
Parent, not terminating
%

但他们都退出了!为什么呢?

1 个答案:

答案 0 :(得分:4)

我认为这里存在逻辑错误 - 当你fork()发生的事情是两位代码分支时 - 那时唯一的区别在于子进程有一个返回代码来自fork()的零,而 parent 的返回代码为$pid

  

它将子pid返回到父进程,0返回子进程,如果fork不成功则返回undef。

所以我认为你测试时你的逻辑是倒退的:

elsif ($pid == 0) {
    print "Parent\n";
}

实际上你的正在进入while循环,而你的子进程仍然在while循环中读取stdin。

而且我认为这就是你遇到问题的原因 - 因为孩子正在接受stop_trace并发出kill "TERM", 0而不是孩子的pid 应该杀死。

当你杀死pid 0时,我实际上并不完全确定应该正在发生什么。但从它的外观来看 - 无论如何它都会向两个进程发出信号。

您的信号处理程序中存在相同的逻辑错误 - 您的父级已被终止,因为$pid已设置为0。我不是百分之百确定为什么导致你的孩子退出 - 你确定它确实存在,并且你没有在while(1)关闭STDIN的情况下积累陈旧的流程吗?

很容易检查 - 在print "$$: killing child with pid $pid\n";分支中粘贴stop_trace

哦 - 如果失败,perl中的fork会返回undef而非-1