我正在使用Perl“Tk”为外部命令(“sox”,如果这可以提供帮助)编写包装器。 当然,我需要异步运行它,以避免阻塞tk的MainLoop()。 但是,我需要读取它的输出以通知用户有关命令的进度。
我正在使用IPC :: Open3:
测试类似这样的解决方案{
$| = 1;
$pid = open3(gensym, ">&STDERR", \*FH, $cmd) or error("Errore running command \"$cmd\"");
}
while (defined($ch = FH->getc)) {
notifyUser($ch) if ($ch =~ /$re/);
}
waitpid $pid, 0;
$retval = $? >> 8;
POSIX::close($_) for 3 .. 1024; # close all open handles (arbitrary upper bound)
但是当然,while循环会阻止MainLoop直到$ cmd终止。
是否有某种方法可以异步读取输出句柄? 或者我应该使用标准的叉子? 解决方案也应该在win32下工作。
答案 0 :(得分:3)
对于文件句柄的非阻塞读取,请查看Tk::fileevent
。
这是一个示例脚本,如何一起使用管道,分叉进程和fileevent:
use strict;
use IO::Pipe;
use Tk;
my $pipe = IO::Pipe->new;
if (!fork) { # Child XXX check for failed forks missing
$pipe->writer;
$pipe->autoflush(1);
for (1..10) {
print $pipe "something $_\n";
select undef, undef, undef, 0.2;
}
exit;
}
$pipe->reader;
my $mw = tkinit;
my $text;
$mw->Label(-textvariable => \$text)->pack;
$mw->Button(-text => "Button", -command => sub { warn "Still working!" })->pack;
$mw->fileevent($pipe, 'readable', sub {
if ($pipe->eof) {
warn "EOF reached, closing pipe...";
$mw->fileevent($pipe, 'readable', '');
return;
}
warn "pipe is readable...\n";
chomp(my $line = <$pipe>);
$text = $line;
});
MainLoop;
分叉在Windows下可能有效,也可能无效。在Tk中分叉时也需要谨慎;你必须确保两个进程中只有一个进行X11 / GUI的操作,否则会发生坏事(X11错误,崩溃......)。一个好的方法是在创建Tk MainWindow之前进行分叉。