【问题标题】:perl parent process hangs waiting for child process to read stdinperl 父进程挂起等待子进程读取标准输入
【发布时间】:2016-03-08 22:07:09
【问题描述】:

我有一个模拟 tee 命令的 perl 脚本,因此我可以将输出写入终端和日志文件。它的工作原理是这样的(错误检查 &c 省略)。

$pid = open(STDOUT, '-|');
# Above is perl magic that forks a process and sets up a pipe with the
# child's STDIN being one end of the pipe and the parent's STDOUT (in
# this case) being the other.
if ($pid == 0)
{
    # Child. 
    # Open log file
    while (<STDIN>)
    {
       # print to STDOUT and log file
    }
    #close log files
    exit;
}
# parent
open STDERR, '>&STDOUT';
# do lots of system("...") calls
close STDERR;
close STDOUT;
exit;

这有时会挂起,并且如果您查看进程和所述进程的堆栈,总是会发现父进程挂在其中一个关闭状态,等待子进程退出,而子进程正在从文件中读取某些内容(必须是 STDIN,因为没有其他文件)。

我不知道如何处理这个问题。如果您从未连接到控制台的 shell 运行程序,问题似乎会发生 - 在普通 shell 中运行脚本可以正常工作 - 并且该脚本中最近更改的唯一代码是添加一个文件的打开/关闭只是为了触摸它(在脚本到达这个“三通”代码之前)。

以前有没有人遇到过这样的问题和/或有关于我可以做些什么来解决这个问题的建议?谢谢。

【问题讨论】:

  • 分离时是否总是发生? STDOUT 是否更早地被重定向 - 在 cron-ed 命令行上还是在程序中?
  • 我看不到问题所在,对我来说,无论哪种方式都可以。我用我想尝试的具体事情和我正在使用的确切代码更新了我的帖子。我正在考虑缓冲/STDIN 搞砸了。例如,最后一次打印(最后一个缓冲区)不会被刷新。

标签: perl io


【解决方案1】:

好吧,经过一些实验,似乎直接打开STDOUT 似乎至少是部分原因。我的代码现在是这样的:

$pid = open($handle, '|-');
if ($pid == 0)
{
    # Child. 
    # Open log file
    while (<STDIN>)
    {
       # print to STDOUT and log file
    }
    #close log files
    exit;
}
# parent
open my $oldout, '>&STDOUT';
open my $olderr, '>&STDERR';
open STDOUT, '>&', $handle;
open STDERR, '>&', $handle;
# do lots of system("...") calls
open STDOUT, '>&', $oldout;
open STDERR, '>&', $olderr;
close $handle or die "Log child exited unexpectedly: $!\n";
exit;

如果没有别的,它看起来更干净(但仍然比我想要的更混乱,因为如果这些 dup 中的任何一个出现错误,我不知道该怎么办)。但是我仍然不清楚为什么在代码中更早地打开和关闭句柄会对这一点产生如此大的影响。

【讨论】:

    猜你喜欢
    • 2016-09-23
    • 2021-05-28
    • 2011-12-15
    • 1970-01-01
    • 2019-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多