Как я могу изменить текущий каталог потокобезопасным способом в Perl? - PullRequest
2 голосов
/ 19 сентября 2010

Я использую 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 продолжать умирать при ошибках какой-либо из команд?

Ответы [ 2 ]

2 голосов
/ 19 сентября 2010

Я думаю, что вы можете довольно легко решить вашу проблему "как мне чидить ребенка перед выполнением команды", отказавшись от 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>;).

Более подробная информация о открытии разветвления находится в perldoc perlipc .

Хорошая вещь об этом в предпочтении к capture("chdir wherever ; $cmd @args")заключается в том, что он не дает оболочке возможности совершать плохие поступки с вашим @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 $?;
2 голосов
/ 19 сентября 2010

Я не думаю"текущий рабочий каталог" - это свойство для каждого потока. Я бы ожидал , что это будет свойство процесса.

Не совсем понятно, зачем вам вообще нужно использовать chdir. Разве вы не можете запустить внешний скрипт, соответствующим образом устанавливая рабочий каталог процесса new ? Это звучит как более осуществимый подход.

...