我正在使用 Thread::Pool::Simple 来创建一些工作线程。每个工作线程都会执行一些操作,包括调用 chdir
,然后执行外部 Perl 脚本(从 jbrowse
基因组浏览器,如果重要的话)。我使用 capturex
调用外部脚本并因失败而死亡。
我发现当我使用多个线程时,事情开始变得困惑。经过一番研究。似乎某些线程的当前目录不正确。
也许chdir
在线程之间传播(即不是线程安全的)?
或者也许是与capturex
有关?
那么,如何安全地设置每个线程的工作目录?
** 更新 **
按照执行时更改目录的建议,我想问一下我应该如何将这两个命令传递给capturex
?
目前我有:
my @args = ( "bin/flatfile-to-json.pl", "--gff=$gff_file", "--tracklabel=$track_label", "--key=$key", @optional_args );
capturex( [0], @args );
如何向 @args
添加另一个命令?
capturex
会继续因任何命令的错误而死亡吗?
最佳答案
我认为您可以通过放弃 IPC::System::Simple
轻松解决“在运行命令之前如何在子进程中 chdir”问题因为不是适合这项工作的工具。
而不是做
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>;
)。
有关 fork-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 $?;
关于multithreading - 如何在 Perl 中以线程安全的方式更改当前目录?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3745048/