在没有等待perl的孩子的情况下分叉并返回

时间:2017-11-30 15:11:42

标签: linux perl fork cgi

我有一个使用fork()启动子进程的perl CGI程序。孩子进行一些长时间运行(约60秒)的计算,最终将结果保存在tmp文件中。父节点应该将控制权返回给浏览器,浏览器显示进度消息并定期检查子节点是否已写入其tmp文件;文件出现后,将显示结果。所以代码看起来像这样:

# Get a unique name for this job
my $guid = Data::GUID->new;
my $id = $guid->as_hex;

# Do the fork 
my $pid = fork;
if (!defined $pid) {
    die "cannot fork: $!";

# Child does this
} elsif ($pid == 0) {
    # Do some calculations
    # Save results in a filename with $id

# Parent does this 
} else {
    # Return the location of the tmp files to the client
    return "Content-Type: text/html\n\n", $id;
    # Browser uses contents of $id to check for the result file
}

我最初在RedHat Linux上设置它,它运行得很好。但是,现在我正在尝试将它移植到运行Ubuntu的服务器上,并且看起来父进程在等待长时间运行的子进程返回之前。我相信这是因为浏览器在计算期间挂起,从不显示进度页面,并在计算完成后立即跳转到结果。

我怀疑这与fork仿真有关,但我不确定,而且我无法找到解决方法。谢谢你的任何建议。

编辑:这段代码是子程序的一部分 - 我使用CGI :: Application,因此调用代码只是“使用”这段代码。因此返回声明。我怀疑这会解决这个问题,因为我从没有触及代码,因为从Red Hat(它工作的地方)移植到Linux(它没有)。

1 个答案:

答案 0 :(得分:0)

Randal Schwartz的Watching long processes through CGI提供了一个有用的例子。分叉是直截了当的:

if ( my $pid = fork ) {       # parent does

    delete_all();             # clear parameters
    param( 'session', $session );
    print redirect( self_url() );
}
elsif ( defined $pid ) {    # child does

    close STDOUT;           # so parent can go on

    unless ( open F, "-|" ) {

        open STDERR, ">&=1";
        exec "/usr/sbin/traceroute", $host;
        die "Cannot execute traceroute: $!";
    }

本文的其余部分介绍了如何帮助用户跟踪正在运行的作业。