Perl, как получить pid потоков из exe c, system, open functions на Win32 и Unix - PullRequest
2 голосов
/ 24 января 2020

Этот вопрос не совсем новый, https://www.perlmonks.org/?node_id=620645, но я не нашел рабочего ответа на мою проблему. Короче говоря, я хочу получить доступ к PID потока / процесса, созданного такой функцией, как system, exe c или open. Тот, который я нашел с помощью функции открытия my $pid = open my $fhOut, "| the command ", or die ...;, в Linux, фактическое значение PID согласно команде ps равно $pid + 2, но в wind32 фактический PID является отрицательным числом (например, -1284). В обоих случаях PID, возвращаемый функцией open, не совпадает с $ pid !!

Аналогично, PID, возвращаемый my $pid = system 1, "command params", не соответствует PID из операционной системы. Может кто-нибудь объяснить, пожалуйста? Как правильно выйти из бесконечной программы l oop, вызываемой из открытых или системных функций. Это мой тестовый код:

my $pid = fork();
if( $pid == 0 ) 
{
  my $mimperf_pid = open my $cmd, "mimperf -C  $db > results/mimperf/mimperf.log |" or die $!;
  sleep(10);
  print $mimperf_pid;
  kill 'KILL', $mimperf_pid; 
  exit 0;
}

В этом коде я пытаюсь уничтожить поток ($ mimperf_pid), созданный с помощью функции open, но это не удалось.

1 Ответ

2 голосов
/ 24 января 2020

fork() не поддерживается Windows, поэтому Perl (плохо) эмулирует его с помощью потоков. Эти виртуальные процессы имеют отрицательные идентификаторы PID. Вам следует избегать fork() на Windows, если вы можете, используя потоки вместо этого, если ничего больше.

Хотя это не относится к вашему вопросу. Хотя PID, возвращаемый fork, является отрицательным, PID, возвращаемый open, не является.


Обычно следует избегать двух аргументов open, поэтому

open my $cmd, "foo bar |"

эквивалентно

open my $cmd, "-|", "foo bar"

И это эквивалентно

open my $cmd, "-|", "cmd", "/x", "/c", "foo bar"

Вы запускаете оболочку для выполнения команды оболочки, и это PID оболочки, которую возвращает open.

То же самое относится и к system 1, $shell_cmd.

Это означает, что сигнал Ctrl-Break отправляется в оболочку. (Это то, что Perl посылает вместо несуществующего SIGKILL.)

Теперь у меня нет mimperf, поэтому я использовал альтернативную программу вместо mimperf (perl), и он получил сигнал Ctrl-Break, а также оболочку. Так что если mimperf не завершился, может быть, это потому, что он не реагирует на Ctrl-Break?


Если вы хотите избежать оболочки, вам нужно будет выполнить перенаправление вывода самостоятельно. Для этого я рекомендую IP C :: Run . Он также обрабатывает таймауты.

use IPC::Run qw( run );

run [ "mimperf", "-C", $db ]
   ">", "results/mimperf/mimperf.log",
   timeout(10);
...