【问题标题】:First program in bash pipeline is blockingbash 管道中的第一个程序阻塞
【发布时间】:2014-06-04 23:47:51
【问题描述】:

我正在尝试将几个 perl 程序连接在一起,从我所阅读的所有内容来看,管道程序应该全部打开并并行运行。无论我做了什么,情况似乎都不是这样。这是简化版:

./video

#!/usr/bin/env perl
my $i = 0;
while($i<10){
    my $time = localtime(time);
    print "VID: $time $i\n";
    sleep 1;
    $i++;
}

./controller

#!/usr/bin/env perl
while(my $line = <STDIN>){
    my $time = localtime(time);
    print "CTRL: $time $line";
}

./pipes

#!/usr/bin/env perl
open(my $controller, "|./controller") || die "Can't fork: $!";
open(STDOUT, ">&", $controller);
open(my $video, "|./video") || die "Can't fork: $!";
print STDERR "All processes started\n";

我尝试以两种方式执行它,但都产生了相同的输出:

<16:34:21> rswhiting@Minas-Tirith:~/code/Pipes $ ./pipes 
All processes started
CTRL: Sun Apr 20 16:34:32 2014 VID: Sun Apr 20 16:34:22 2014 0
CTRL: Sun Apr 20 16:34:32 2014 VID: Sun Apr 20 16:34:23 2014 1
CTRL: Sun Apr 20 16:34:32 2014 VID: Sun Apr 20 16:34:24 2014 2
CTRL: Sun Apr 20 16:34:32 2014 VID: Sun Apr 20 16:34:25 2014 3
CTRL: Sun Apr 20 16:34:32 2014 VID: Sun Apr 20 16:34:26 2014 4
CTRL: Sun Apr 20 16:34:32 2014 VID: Sun Apr 20 16:34:27 2014 5
CTRL: Sun Apr 20 16:34:32 2014 VID: Sun Apr 20 16:34:28 2014 6
CTRL: Sun Apr 20 16:34:32 2014 VID: Sun Apr 20 16:34:29 2014 7
CTRL: Sun Apr 20 16:34:32 2014 VID: Sun Apr 20 16:34:30 2014 8
CTRL: Sun Apr 20 16:34:32 2014 VID: Sun Apr 20 16:34:31 2014 9
<16:34:49> rob@Minas-Tirith:~/code/Pipes $ ./video | ./controller 
CTRL: Sun Apr 20 16:35:25 2014 VID: Sun Apr 20 16:35:15 2014 0
CTRL: Sun Apr 20 16:35:25 2014 VID: Sun Apr 20 16:35:16 2014 1
CTRL: Sun Apr 20 16:35:25 2014 VID: Sun Apr 20 16:35:17 2014 2
CTRL: Sun Apr 20 16:35:25 2014 VID: Sun Apr 20 16:35:18 2014 3
CTRL: Sun Apr 20 16:35:25 2014 VID: Sun Apr 20 16:35:19 2014 4
CTRL: Sun Apr 20 16:35:25 2014 VID: Sun Apr 20 16:35:20 2014 5
CTRL: Sun Apr 20 16:35:25 2014 VID: Sun Apr 20 16:35:21 2014 6
CTRL: Sun Apr 20 16:35:25 2014 VID: Sun Apr 20 16:35:22 2014 7
CTRL: Sun Apr 20 16:35:25 2014 VID: Sun Apr 20 16:35:23 2014 8
CTRL: Sun Apr 20 16:35:25 2014 VID: Sun Apr 20 16:35:24 2014 9
<16:35:25> rob@Minas-Tirith:~/code/Pipes $ 

视频节目的时间戳按应有的递增,但控制程序接收它们的时间是相同的(在视频节目结束后)。如何让控制器在数据生成时而不是事后接收数据?

【问题讨论】:

    标签: perl bash pipe fork


    【解决方案1】:

    这是因为 video 程序中的 STDOUT 缓冲。 print 只有在进入交互式终端时才会被行缓冲。否则它会使用更大的缓冲区,并且当video 退出时,累积的输出会以一大块发出。每次打印后尝试冲洗或使用自动冲洗。

    $| = 1;  # Enables autoflush
    

    顺便说一句,我不明白你为什么打开一个管道到video,它什么也没读。应该是

    system "./video";
    

    如果您有一个无法修改但无法自动刷新的程序,那么您就有麻烦了。除了,你不是。您可以使用伪终端代替管道。我从来没有做过。但是“The UXIX Programming Interface”一书的第 64 章是关于伪终端的。

    【讨论】:

    • 太神奇了!有没有办法在视频程序之外做到这一点?在完整的场景中,视频程序是一个编译后的 C++ 程序,它输出坐标列表。如果没有,至少我知道这个问题叫什么:)
    • 不,缓冲发生在video 进程内的用户空间库中。如果您可以对程序说谎,它的输出会发送到终端,但是...
    • 我的示例之前的迭代使用 exec "./video" 而不是打开视频作为句柄。
    • 好的。在我的 C++ 程序中,我只需要在完成目标列表时添加一个cout.flush()。无需对它撒谎并告诉它这是更大计划的一部分:)
    • @RobW,如果它认为它连接到终端,它不会缓冲,所以你使用伪 tty 而不是管道。
    猜你喜欢
    • 2016-06-05
    • 2010-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-05
    • 1970-01-01
    • 1970-01-01
    • 2010-12-11
    相关资源
    最近更新 更多