我应该如何检查给定的 PID 是否正在运行?

ter*_*don 16 process perl process-management proc

我正在编写一个 Perl 脚本,它解析日志文件以收集 PID,然后检查该 PID 是否正在运行。我正在努力想出最好的方法来进行检查。显然,我可以这样做:

system("ps $pid > /dev/null") && print "Not running\n";
Run Code Online (Sandbox Code Playgroud)

但是,如果可能,我更愿意避免系统调用。因此,我认为我可以使用/proc文件系统(可移植性不是问题,这将始终在 Linux 系统上运行)。例如:

if(! -d "/proc/$pid"){
    print "Not running\n";
}
Run Code Online (Sandbox Code Playgroud)

那安全吗?我可以总是假设如果没有/proc/$pid/目录关联的 PID 没有运行吗?我希望如此,因为 AFAIKps本身从/proc任何方式获取信息,但由于这是用于生产代码,我想确定。

那么,是否存在正在运行的进程没有/proc/PID目录或/proc/PID目录存在但进程没有运行的情况?是否有任何理由更喜欢解析而ps不是检查目录是否存在?

Ste*_*ris 20

kill(0,$pid)可以使用perl 函数。

如果返回码为 1,则 PID 存在,您可以向其发送信号。

如果返回码为 0,则您需要检查 $!。它可能是 EPERM(权限被拒绝),这意味着进程存在或 ESRCH 在这种情况下进程不存在。

如果您的检查代码正在运行,root那么您可以将其简化为仅检查 kill 的返回码;0=>错误,1=>正常

例如:

% perl -d -e 0

Loading DB routines from perl5db.pl version 1.37
Editor support available.

Enter h or 'h h' for help, or 'man perldebug' for more help.

main::(-e:1):   0
  DB<1> print kill(0,500)
0
  DB<2> print $!
No such process
  DB<3> print kill(0,1)
0
  DB<4> print $!
Operation not permitted
  DB<5> print kill(0,$$)
1
Run Code Online (Sandbox Code Playgroud)

这可以做成一个简单的函数

use Errno;

sub test_pid($)
{
  my ($pid)=@_;

  my $not_present=(!kill(0,$pid) && $! == Errno::ESRCH);

  return($not_present);
}

print "PID 500 not present\n" if test_pid(500);
print "PID 1 not present\n" if test_pid(1);
print "PID $$ not present\n" if test_pid($$);
Run Code Online (Sandbox Code Playgroud)

  • 如果挂载了 `/proc`,那么命名空间中可见的每个 PID 都将出现,所以你的 `-d /proc/$pid` 测试 _would_ 工作......但它涉及到文件系统而不是使用本地系统调用。 (2认同)
  • @terdon:我刚刚意识到我的困惑来自这样一个事实,即“系统调用”实际上是指“`system`调用”——即对`system`函数本身的调用,而不是[“系统调用”]( https://en.wikipedia.org/wiki/System_call)。后者你无法避免,但前者你当然可以。现在有道理! (2认同)

G-M*_*ca' 6

  • 我 99.9% 确信检查是否存在(并且是一个目录)与该技术一样可靠 98% 。98% 不是 100% 的原因是 Stephen Harris在评论中触及(并反弹)的一点——即文件系统可能未安装。这可能是有效的要求是Linux系统,而不 是一个破坏,退化的系统-毕竟,像,以及可能将无法正常工作-所以这可能不是对生产系统的问题。但是(理论上)它可能永远不会被挂载(尽管这可能会阻止系统进入正常状态),它绝对有可能被卸载(我已经测试过1/proc/PIDkill?0/proc/procpstoplsof),并且我相信没有任何保证它会存在(即,POSIX 不需要它)。并且,除非系统被完全冲洗,kill否则将工作。
  • Stephen 的评论谈到了“使用文件系统”和“使用本机系统调用”。我相信这在很大程度上是一个转移注意力的问题。
    • 是的,任何试图访问/proc 需要读取根目录下找到的/proc文件系统。这是真实的任何企图访问任何一个绝对路径的文件,其中包括东西/bin,/etc和/dev。这种情况经常发生,以至于根目录肯定会在系统的整个生命周期(正常运行时间)中缓存在内存中,因此可以在没有任何磁盘 I/O 的情况下完成此步骤。而且,一旦您拥有 的 inode /proc,发生的所有其他事情都在内存中。
    • 你如何访问/proc?使用stat、open、readdir等,这些都是本机系统调用,与kill.
  • 该问题涉及正在运行的进程。这是一个狡猾的词组。如果您真的想测试进程是否正在运行 (即,在运行队列中;可能是某个 CPU 上的当前进程;未休眠、等待或停止),您可能需要执行 a并读取输出,或查看. 但是我在您的问题或评论中没有看到您对此感到担忧的暗示。ps?PID /proc/PID/stat

    然而,房间里的大象是僵尸2进程可能很难与活跃的进程区分开来。  kill?0作用于僵尸,并且存在。您可以使用上一段中列出的技术(执行和读取输出,或查看)来识别僵尸。我非常快速和随意(即,不是很彻底)的测试表明,您也可以通过执行 a或 on 、、 或- 这些将在僵尸上失败来做到这一点。(但是,它们也会在您不拥有的进程上失败。)/proc/PIDps?PID/proc/PID/statreadlinklstat/proc/PID/cwd/proc/PID/root/proc/PID/exe

____________
1?如果-f(˚F奥尔塞)选项不工作,尝试-l(升AZY)。
2 ? 即,一个进程已经退出/死亡/终止,但其父进程尚未执行wait.