Perl如何终止子进程并退出父进程?

3
我正在使用PERL编写仿真桩来测试另一个程序。下面的代码运行了一个循环,检查命令(初始化,退出,开始跟踪,停止跟踪)。当读取“start_trace”命令时,它会fork一个进程,每秒钟输出一些数字。我想使用“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";
        }
    }
}

输出结果(标准输入和标准输出混合在一起,但我正在输入“stop_trace”)

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个回答

4
我认为这里有一个逻辑错误 - 当你执行fork()时,会发生两个代码分支的情况 - 在那一点上唯一的区别是子进程从fork()返回零作为返回码,而父进程则返回$pid作为返回码。

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

所以我认为当你测试时,你的逻辑是相反的:

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

实际上,进入while循环的是你的父进程,而你的子进程仍然在一个while循环中读取标准输入。 我认为这就是你遇到问题的原因——因为子进程捕获了stop_trace并发出了kill "TERM", 0,而不是它应该杀死的子进程pid。
我实际上不确定当你杀死pid 0时应该发生什么。但看起来它会向两个进程发送信号。
在你的信号处理程序中,你有同样的逻辑错误——因为它将$pid设置为0,所以你的父进程被杀死。虽然我不100%确定为什么会导致你的子进程退出——你确定它实际上是这样做的,而不是在关闭STDINwhile(1)中积累过时的进程吗?
不过很容易检查——在那个stop_trace分支中放置一个print "$$: killing child with pid $pid\n";

哦,而且在Perl中,fork如果失败了返回的是undef而不是-1


哦,太好了,你是正确的。我在处理程序和循环中将“== 0”更改为“!= 0”,现在一切都正常了。谢谢。我应该删除这篇帖子吗? - PeterT
我认为这并不是必要的 - 这是一个合理的问题,对未来的读者可能有用。 - Sobrique

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接