【问题标题】:fork() and STDOUT/STDERR to the console from child processesfork() 和 STDOUT/STDERR 从子进程到控制台
【发布时间】:2011-04-22 01:08:37
【问题描述】:

我正在编写一个分叉多个子进程的程序,我希望所有这些子进程都能够向STDERRSTDOUT 写入行而不会出现乱码。我没有做任何花哨的事情,只是发出以新行结尾的行(至少在我的理解中,这将是 Linux 的原子操作)。从 perlfaq 它说:

主进程和后台进程(“子”进程)共享相同的 STDIN、STDOUT 和 STDERR 文件句柄。如果两者都尝试同时访问它们,可能会发生奇怪的事情。您可能想为孩子关闭或重新打开这些。您可以通过打开管道来解决此问题(请参阅 open),但在某些系统上,这意味着子进程无法比父进程存活。

它说我应该为孩子“关闭或重新打开”这些文件句柄。关闭很简单,但“重新打开”是什么意思?我已经在我的子进程中尝试过这样的事情,但它不起作用(输出仍然是乱码):

open(SAVED_STDERR, '>&', \*STDERR) or die "Could not create copy of STDERR: $!";
close(STDERR);

# re-open STDERR
open(STDERR, '>&SAVED_STDERR') or die "Could not re-open STDERR: $!";

那么,我做错了什么?它暗示的管道示例会是什么样子?有没有更好的方法将多个进程的输出协调到控制台?

【问题讨论】:

    标签: linux perl console fork


    【解决方案1】:

    对文件句柄的写入对于 STDOUT 和 STDIN 来说不是原子的。 fifos之类的情况有特殊情况,但这不是您当前的情况。

    当它说重新打开 STDOUT 时,这意味着“创建一个新的 STDOUT 实例”这个新实例与来自父级的实例不同。这就是您如何在系统上打开多个终端,而不是让所有 STDOUT 到同一个地方。

    管道解决方案将通过管道(如 shell 中的 |)将子级连接到父级,您需要让父级从管道中读取并多路复用输出本身。父级将负责从管道中读取数据,并确保它不会同时将来自管道的输出和发往父级 STDOUT 的输出交错。有一个示例和文章here 的管道。

    一个片段:

    use IO::Handle;
    
    pipe(PARENTREAD, PARENTWRITE);
    pipe(CHILDREAD, CHILDWRITE);
    
    PARENTWRITE->autoflush(1);
    CHILDWRITE->autoflush(1);
    
    if ($child = fork) { # Parent code
       chomp($result = <PARENTREAD>);
       print "Got a value of $result from child\n";
       waitpid($child,0);
    } else {
       print PARENTWRITE "FROM CHILD\n";
       exit;
    }
    

    看看孩子如何不写入标准输出,而是使用管道向父母发送消息,父母使用标准输出进行写入。请务必看一下,因为我省略了关闭不需要的文件句柄之类的内容。

    【讨论】:

    • 我最终选择了 IO::Pipe 和 AnyEvent 来进行管道和 IO 选择,但这似乎可行。谢谢
    【解决方案2】:

    虽然这对你的乱码没有帮助,但我花了很长时间才找到一种方法来启动一个可以由父进程写入的子进程,并将子进程的 stderr 和 stdout 直接发送到屏幕(这解决了您在尝试从两个不同的 FD 读取而不使用 select 之类的花哨的东西时可能遇到的令人讨厌的阻塞问题)。

    一旦我想通了,解决方案就很简单了

    my $pid = open3(*CHLD_IN, ">&STDERR", ">&STDOUT", 'some child program');
    # write to child
    print CHLD_IN "some message";
    close(CHLD_IN);
    waitpid($pid, 0);
    

    “某个子程序”中的所有内容都将发送到 stdout/stderr,您可以通过写入 CHLD_IN 来简单地抽取数据,并相信如果子程序的缓冲区已满,它会阻塞。对于父程序的调用者来说,这一切看起来就像 stderr/stdout。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-07-07
      • 1970-01-01
      • 2023-04-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多