首页 > 解决方案 > Perl,如何从 exec、system、Win32 和 Unix 上的打开函数中获取线程的 pid

问题描述

这个问题并不新鲜,https://www.perlmonks.org/?node_id=620645,但我没有找到解决问题的有效答案。简而言之,我想访问由 system、exec 或 open 等函数创建的线程/进程的 PID。我使用open函数发现的一个my $pid = open my $fhOut, "| the command ", or die ...;,在Linux中,根据ps命令实际PID值为$pid + 2,但在wind32中,实际PID是负数(如-1284)。在这两种情况下,open 函数返回的 PID 都与 $pid 不同!!

同样,返回的 pidmy $pid = system 1, "command params"与操作系统的 PID 不匹配。有人可以解释一下吗?退出从打开或系统函数调用的无限循环程序的正确方法是什么。这是我的测试代码:

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;
}

在这段代码中,我试图杀死通过该open函数创建的线程 ($mimperf_pid),但它没有成功。

标签: perlforksystempid

解决方案


fork()Windows 不支持,因此 Perl(很差)使用线程来模拟它。这些虚拟进程具有负 PID。如果可以的话,你应该避免fork()在 Windows 上使用,如果没有别的,就使用线程。

不过,这与您的问题无关。虽然返回的 PIDfork是负数,但返回的 PIDopen不是。


一个人通常应该避免两个参数open,所以

open my $cmd, "foo bar |"

相当于

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

这相当于

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

您正在启动一个 shell 来执行一个 shell 命令,它是open返回的 shell 的 PID。

也一样system 1, $shell_cmd

这意味着 Ctrl-Break 信号正在发送到 shell。(这就是 Perl 发送的代替不存在的 SIGKILL 的内容。)

现在,我没有,mimperf所以我使用了替代程序而不是mimperf( perl),它收到了 Ctrl-Break 信号以及 shell。所以如果mimperf没有退出,也许是因为它对 Ctrl-Break 没有响应?


如果要避免使用 shell,则需要自己进行输出重定向。为此,我推荐IPC::Run。它也处理超时。

use IPC::Run qw( run );

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

推荐阅读