【问题标题】:Timing out a forked process使分叉的进程超时
【发布时间】:2017-12-28 02:12:07
【问题描述】:

我在多个处理器上运行 Monte Carlo,但它挂了很多。所以我把这个 perl 代码放在一起,以终止挂起 monte carlo 的迭代并进入下一个迭代。但是我得到了一些错误,我还没有弄清楚。 我认为它睡眠时间太长,它会在查找它之前删除 out.mt0 文件。 这是代码:

my $pid = fork();
die "Could not fork\n" if not defined $pid;

if ($pid == 0) {
    print "In child\n";   
    system("hspice -i mont_read.sp -o out -mt 4"); wait;
    sleep(.8); wait;
    exit(0);
}

print "In parent \n";

$i = 0;    
$mont_number = $j - 1;

out: while (1) {
    $res = waitpid($pid, WNOHANG);    
    if ($res == -1) {
        print "Successful Exit Process Detected\n";
        system("mv out.mt0 mont_read.mt0"); wait;
        sleep(1); wait;
        system("perl monte_stat.pl > rel_out.txt"); wait ;
        system("cat stat_result.txt rel_out.txt > stat_result.tmp"); wait; 
        system("mv stat_result.tmp stat_result.txt"); wait;
        print "\nSim #$mont_number complete\n"; wait;
        last out;    
    }

    if ($res != -1) {    
        if ($i >= $timeout) {
            $hang_count = $hang_count+1;
            system("killall hspice"); wait;
            sleep(1);
            print("time_out complete\n"); wait;
            print "\nSim #$mont_number complete\n"; wait;
            last out; 
        }

        if ($i < $timeout) {
            sleep $slept; wait;
        }
        $i = $i+1;
    }
}

这是错误:

在 monte_stat.pl 第 73 行第 2 行非法除零。 mv:无法统计`out.mt0':没有这样的文件或目录 在 monte_stat.pl 第 73 行第 1 行非法除零。 mv:无法统计`out.mt0':没有这样的文件或目录 在 monte_stat.pl 第 73 行第 1 行非法除零。 mv:无法统计`out.mt0':没有这样的文件或目录 在 monte_stat.pl 第 73 行非法除以零。 mv:无法统计`out.mt0':没有这样的文件或目录 在 monte_stat.pl 第 73 行非法除以零。 mv:无法统计`out.mt0':没有这样的文件或目录 mv:无法统计`out.mt0':没有这样的文件或目录 mv:无法统计`out.mt0':没有这样的文件或目录 在 monte_stat.pl 第 73 行第 3 行非法除零。 mv:无法统计`out.mt0':没有这样的文件或目录 在 monte_stat.pl 第 73 行第 1 行非法除零。 mv:无法统计`out.mt0':没有这样的文件或目录

谁能告诉我在哪里调试它。 谢谢

【问题讨论】:

  • 发布一个最小的、完整的、可验证的例子。不要只是链接到您的代码。
  • 我在您发布的代码中看不到任何线程。
  • @duskwuff 我添加了线程部分。这是完整的代码:github.com/aliyah3/Multi-thread-with-Perl/blob/master/…
  • 你是在分叉,而不是线程。有很大的不同。
  • @simbabque 谢谢。我修改了问题。

标签: perl fork


【解决方案1】:

根据错误,您的hslice 似乎正在崩溃。但还有其他问题。

这是一个尽可能接近您的代码的工作示例。

use warnings;
use strict;
use feature 'say';
use POSIX qw(:sys_wait_h);
$| = 1;

my ($timeout, $duration, $sleep_time) = (5, 10, 1);

my $pid = fork // die "Can't fork: $!";

if ($pid == 0)  
{
    exec "echo JOB STARTS; sleep $duration; echo JOB DONE";
    die "exec shouldn't return: $!";
}    
say "Started $pid";
sleep 1;

my $tot_sec;    
while (1) 
{
    my $ret = waitpid $pid, WNOHANG;

    if    ($ret > 0) { say "Child $ret exited with: $?";  last; }
    elsif ($ret < 0) { say "\nNo such process ($ret)";    last; }
    else             { print " . " }

    sleep $sleep_time;

    if (($tot_sec += $sleep_time) > $timeout) {
        say "\nTimeout. Send 15 (SIGTERM) signal to the process.";
        kill 15, $pid;
        last;
    }   
}

$duration(作业的)设置为3,比$timeout短,我们得到

开始 16848 工作开始 . . .任务完成 子 (JOB) 16848 退出时:0

$duration 设置为 10 时,我们得到

开始 16550 工作开始 . . . . . 暂停。向进程发送 15 (SIGTERM) 信号。

作业被终止(再等 5 秒 - JOB DONE 不应该出现)。

对问题中代码的评论

  • 如果您 fork 只是为了运行一项工作,则没有理由使用 system。就exec那个程序

  • system之后不需要wait,这是错误的。 system 包含等待

  • wait不属于printsleep之后,错了

  • 无需为killall 掏腰包即可杀死进程

  • 如果您最终使用system,程序将在具有另一个 PID 的新进程中运行。然后需要更多来找到该PID并杀死它。参见Proc::ProcessTablethis post,例如

  • 上面的代码需要检查进程是否确实被杀死了

替换您的命令行而不是 echo ... 并根据需要添加检查。

另一种选择是简单地休眠$timeout 期间,然后检查作业是否完成(子退出)。但是,通过您的方法,您可以在轮询时做其他事情。

另一种选择是使用alarm

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-24
    • 1970-01-01
    • 1970-01-01
    • 2012-04-22
    • 1970-01-01
    • 2014-07-19
    • 1970-01-01
    • 2011-06-24
    相关资源
    最近更新 更多