fork()和STDOUT / STDERR从subprocess到控制台

我正在写一个程序,分叉多个subprocess,我希望所有这些subprocess能够写入STDERRSTDOUT行,而不会输出乱码。 我没有做任何奇怪的事情,只是发出以新行结束的行(至less在我的理解中是Linux的primefaces操作)。 从perlfaq它说:

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

它说我应该“closures或重新打开”这些孩子的文件句柄。 closures很简单,但是“重新打开”是什么意思? 我从我的subprocess中尝试过这样的东西,它不起作用(输出仍然是乱码):

 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: $!"; 

那么,我在做什么错呢? 它会暗示的pipe道示例是什么样的? 有没有更好的方法来协调来自多个进程的输出到控制台

写入文件句柄对于STDOUT和STDIN 不是原子的。 像fifos这样的事情有特殊情况,但这不是你现在的情况。

当它说重新打开STDOUT的意思是“创建一个新的STDOUT实例”这个新的实例是不一样的父母。 这就是如何在系统上打开多个终端,而不是将所有的STDOUT都放到同一个地方。

管道解决方案将通过一个管道将子节点连接到父节点(比如在shell中),并且需要让父节点从管道中读出并复用输出本身。 父节点将负责从管道中读取数据,并确保它不会同时将管道的输出和输出发送到父节点的STDOUT。 这里有一个例子和书面的管道。

snippit:

 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; } 

看看孩子如何不写入标准输出,而是使用管道向父母发送消息,父母用标准输出进行写操作。 一定要看看,因为我省略了像关闭不需要的文件句柄的东西。

虽然这并不能帮助你解决问题,但花了很长时间才找到一种方法来启动父进程可以写入的子进程,并将子进程的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); 

一切从“一些孩子程序”将被发射到标准输出/标准错误,您可以简单地泵送数据写入CHLD_IN和相信,如果孩子的缓冲区填满将阻止。 对于父程序的调用者,它们看起来都像stderr / stdout。