如何允许两个并发进程进行通信?

8
我有两个不同的进程:一个C程序每秒输出逗号分隔值后跟换行符,另一个Perl程序接收数据(以相同格式)并处理这些数据。
C程序通过printf输出如下值:
1, 2, 3, 4, 5, 6  
7, 8, 9, 10, 11, 12  
...

这个 Perl 程序坐在一个无限循环中,等待 STDIN 的每一行数据以便处理这些数据:
while ($line = <STDIN>)
{
    chomp($line) # Line should now read "1,2,3,4,5,6"
    # Process data
}

我希望这两个进程实时通信。标准的bash管道不起作用(例如:process1 | process2),因为Perl程序在处理输入之前会等待第一个程序完成。
有没有人对解决这个问题有任何想法、建议或见解?提前感谢!

严格来说,这与“实时”无关。 - andersoj
你说得完全正确,我匆忙写下了这段代码,无法想到更好的方法来解释我希望这些进程如何工作。并发可能是更好的选择。 - drarc
并发更好,并且有一个编辑按钮可以让您修复它。 - derobert
2个回答

17

这个情况下使用管道是没问题的;你只需要控制C程序的输出何时刷新,使其逐步对perl脚本可用即可。在C程序中使用 fflush() 即可实现此操作,它将强制将缓冲区从C程序推出,以便perl程序可以读取它。

使用管道并不会导致perl程序在处理输出之前等待C程序完成写入。你的perl程序被编写成每次处理 STDIN 的一行:

while ($line = <STDIN>) { ... }

在这个上下文中,<>STDIN读取一行,但如果没有可用的行,则会阻塞直到有可用的行。C程序调用fflush()可以使其发生。
查看Wikipedia文章关于管道。实现部分简要描述了管道如何缓冲,这应该可以帮助您了解进程如何通信。管道确实允许进程之间并发,从管道读取和写入的进程由调度程序像其他进程一样管理。您在这里遇到的问题是缓冲区。

我认为C程序在打印换行符时会刷新所有输出。 - Chris Lutz
你的回答非常正确——我甚至尝试过fflush,但从未想过在stdout上使用它。由于perl程序行为的特性,我误认为它在等待c程序。在我的printf语句后添加了fflush(stdout),结果完美无缺!谢谢!! - drarc
@Chris Lutz,自动刷新仅在流处于行缓冲模式时才会发生,这通常只在流打开在tty上时才为真。一旦stdout是管道,它默认为完全缓冲以获得最佳性能。 - RBerteig

5

这个C程序应该显式地使用fflush()来刷新它的输出缓存,或者使用一个pty。虽然后者更加麻烦,但可以让C代码更简单。如果您对此不熟悉,请尝试使用“man 3 fflush”命令。


使用pty是过度设计;如果在C代码中使用stdio,则刷新输出很重要(如果直接使用write()则不重要)。 - Jonathan Leffler
只有在两个进程必须相互交互时才需要pty,而且只有在一个或两个进程必须忽略非人类作为交互方时才需要。除了类Unix平台外,pty也不太可移植。 - RBerteig
我同意pty是过度的,但它会欺骗C程序在每个换行符后自动刷新。从这个意义上讲(仅限于此!),它会使C程序变得更简单,但环境更加复杂。 - Chris Dolan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接