我正在使用Thread::Pool::Simple
创建一些工作线程。每个工作线程都会做一些事情,包括调用chdir
,然后执行外部Perl脚本(来自jbrowse
基因组浏览器,如果重要的话)。我使用capturex
来调用外部脚本并在其失败时死亡。
我发现当我使用多个线程时,事情开始变得混乱。经过一番研究。似乎某些线程的当前目录不正确。
也许chdir
在线程之间传播(即不是线程安全的)?
或者它可能是capturex
的东西?
那么,我如何安全地为每个线程设置工作目录?
**更新**
按照建议在执行时更改dir,我想问一下我应该如何将这两个命令传递给capturex
?
目前我有:
my @args = ( "bin/flatfile-to-json.pl", "--gff=$gff_file", "--tracklabel=$track_label", "--key=$key", @optional_args );
capturex( [0], @args );
如何向@args
添加其他命令?
capturex
会因任何命令的错误而继续死亡吗?
答案 0 :(得分:2)
我认为“当前工作目录”是一个每线程属性。我期待它是该过程的属性。
目前尚不清楚为什么你需要使用chdir
。您是否可以启动外部脚本而不是相应地设置 new 进程的工作目录?这听起来更可行。
答案 1 :(得分:2)
我认为你可以通过放弃IPC::System::Simple
而不是正确的工具来解决你的“如何在运行命令之前解决孩子问题”这个问题。
而不是做
my $output = capturex($cmd, @args);
做类似的事情:
use autodie qw(open close);
my $pid = open my $fh, '-|';
unless ($pid) { # this is the child
chdir($wherever);
exec($cmd, @args) or exit 255;
}
my $output = do { local $/; <$fh> };
# If child exited with error or couldn't be run, the exception will
# be raised here (via autodie; feel free to replace it with
# your own handling)
close ($fh);
如果你得到一个行列表而不是capturex
的标量输出,那么唯一需要改变的是倒数第二行(到my @output = <$fh>;
)。
有关forking-open的更多信息,请参阅perldoc perlipc。
优先考虑capture("chdir wherever ; $cmd @args")
的好处是,它不会让shell有机会对你的@args
做坏事。
my $pid = fork;
die "Couldn't fork: $!" unless defined $pid;
unless ($pid) { # this is the child
chdir($wherever);
open STDOUT, ">/dev/null"; # optional: silence subprocess output
open STDERR, ">/dev/null"; # even more optional
exec($cmd, @args) or exit 255;
}
wait;
die "Child error $?" if $?;