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


16

我正在编写一个Perl脚本,该脚本分析日志文件以收集PID,然后检查该PID是否正在运行。我正在尝试最好的检查方法。显然,我可以这样做:

system("ps $pid > /dev/null") && print "Not running\n";

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

if(! -d "/proc/$pid"){
    print "Not running\n";
}

这样安全吗?我是否可以总是假设如果没有/proc/$pid/目录,则关联的PID未运行?我希望如此,因为AFAIK ps本身/proc还是从信息中获取信息,但是由于这是针对生产代码的,因此我想确定一下。

因此,是否可能存在正在运行的进程没有/proc/PID目录或/proc/PID存在目录且进程未运行的情况?有没有理由更喜欢解析而ps不是检查目录是否存在?


2
还有一个kill使用信号0 的perl 函数,该信号不会杀死,但会说是否可以这样做(即您需要允许该过程发出信号)。
meuh '16

1
如果在Linux中执行'/ proc / $ PID'应该很好。
likewhoa

7
@terdon请注意,无论使用哪种方法(kill -0最好的方法),这只会告诉您是否存在具有给定PID的正在运行的进程。它不会告诉您该进程是否在一毫秒后仍将继续运行,也不会告诉您该进程是您感兴趣的进程还是在有趣的进程死亡后分配了相同PID的不相关进程。测试给定的PID是否正在运行几乎总是一个错误:在极少数情况下,这不容易出现竞争状况。
吉尔斯(Gillles)“所以-别再邪恶了”

1
@Gilles确实,我还应该检查进程名称。但是,在这种情况下,我不在乎毫秒后是否发生状态更改。我列出了以dB为单位的活动进程,以及带有pid的相应文件。我只需要检查数据库认为正在运行的任何东西是否实际上没有运行,并且对设置有足够的控制权就可以知道它不能再次随机启动。
terdon

3
@MickLH哇,这是我被告知的。如果您不愿意解释什么是那么糟糕和危险,那实际上是一个有用的评论,而不是在庆祝自己的才华。我毫不怀疑您是对的,我从来没有声称自己是一名程序员,这就是为什么我问这个问题,但是您设法既侮辱又无益。
terdon

Answers:


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

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

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($$);

FWIW,我添加了一个简单的函数来演示如何执行此操作。
史蒂芬·哈里斯

是的,我想我会考虑的。我删除了评论,因为我意识到我所需要的只是if (!kill(0,$pid) && $! =~ /No such process/){ exit; }或相似。Errno不过,我更喜欢您的解决方案。虽然我可能会考虑这个问题,但我会等一会儿,以防有人可以回答底层的Linux问题。
terdon

2
如果/proc已安装,则将显示命名空间中所有可见的PID,因此您的-d /proc/$pid测试可以进行...但是它涉及到文件系统,而不是使用本机系统调用。
史蒂芬·哈里斯

正是我想要避免的,是的。
terdon

2
@terdon:我刚刚意识到我的困惑来自于这样一个事实,即“系统调用”实际上是“ system调用”的意思,即对system函数本身的调用,而不是“系统调用”。后者您无法避免,但前者您当然可以。现在有意义!
user541686 '16

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?随着statopenreaddir,等等,这些都是原生系统调用每一个位之多kill
  • 这个问题谈论一个进程正在运行。这是一个湿滑的短语。如果您实际上要测试进程是否正在运行 (即,在运行队列中;也许当前进程在某个CPU上;而不是在睡眠,等待或停止),则可能需要执行a 并读取输出,或查看。但是我在您的问题或评论中没有暗示您对此感到担忧。ps PID /proc/PID/stat

    然而,房间里的大象却很难区分僵尸2进程和活着的进程。  kill 0在僵尸上工作并存在。您可以使用上一段中列出的技术(执行和读取输出或查看)来识别僵尸。我很快和休闲(即不很透彻)的测试表明,你也可以做一个这样做或 上,或-这些将僵尸失败。(但是,它们也会在您不拥有的进程上失败。)/proc/PIDps PID/proc/PID/statreadlinklstat/proc/PID/cwd/proc/PID/root/proc/PID/exe

____________
1  如果-f˚F奥尔塞)选项不工作,尝试-l AZY)。
2,  即已经退出/死亡/终止但其父级尚未完成的过程wait


感谢您对我的回答的评论,我已将其删除,因为它是错误的。我认为手册kill(2)页不直接指示您指出的行为,但手册perlfunc页却可以。我将给Michael Kerrisk发送电子邮件,以了解他对系统手册的看法。
jrw32982在2013年

我提交了错误报告澄清手册页的kill(2)关于权限的“发送”信号0
jrw32982支持莫妮卡

@ jrw32982:好的,手册页上写着“ sig参数……可能为0,在这种情况下将执行错误检查……”和“ ERRORSkill()系统调用将失败,并且在以下情况下不会发送信号: …发送过程不是超级用户,并且其有效用户ID与接收过程的有效用户ID不匹配。……”既然您提到了它,我想可以用多种方法来解释它,但是遗憾的是,许多Unix手册页都是用这种风格编写的,需要您在各行之间进行阅读。迈克尔可能会相信事实已经很清楚了。
G-Man说'

迈克尔对kill(2)联机帮助页进行了更改(我尚未在线看到它):“如果sig为0,则不会发送信号,但是仍然会执行存在和权限检查;这可以用来检查是否存在允许呼叫者发信号的进程ID或进程组ID。”
jrw32982在2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.