进程A在运行时打开&&映射了数千个文件。然后发出killl -9 <pid of process A>
。然后我对以下两个事件的顺序有疑问。
a)无法访问/proc/<pid of process A>
。
b)关闭由进程A打开的所有文件。
有关此问题的更多背景:
进程A是一个多线程后台服务。它由cmd ./process_A args1 arg2 arg3
启动。
还有一个看门狗进程,用于检查进程A是否仍定期(每1秒)处于活动状态。如果进程A已死,则重新启动它。看门狗检查进程A的方式如下。
1)收集/proc/
下的所有数值子目录
2)将/proc/<all-pids>/cmdline
与进程A的cmdline进行比较。如果它们与/proc/<some-pid>/cmdline
匹配,则进程A仍然存在并且不执行任何操作,否则重新启动进程A。
进程A在进行初始化时将执行以下操作。
1)打开文件A
2)群文件A
3)mmap fileA进入内存
4)关闭文件A
初始化后,进程A将映射成千上万个文件。
几分钟后,将发出kill -9 <pid of process A>
。
看门狗检测到进程A的死亡,然后重新启动它。但是有时进程A停留在step 2 flock fileA
处。经过一些调试后,我们发现杀死进程A时将执行文件A的解锁。但是有时此事件会在step 2 flock fileA
新流程之后发生。
因此,我们猜想监视器/proc/<pid of process A>
是否可以动态检查进程
不正确。
答案 0 :(得分:3)
然后发布
kill -9
这是坏习惯。您最好先发送SIGTERM
。因为行为良好的流程和设计良好的程序可以捕获它(并在获得SIGTERM
时退出好和正确)。在某些情况下,我甚至建议:发送SIGTERM
。等待两三秒钟。发送SIGQUIT
。等待两秒钟。最后,发送一个SIGKILL
信号(用于那些未正确编写或行为异常的不良程序)。几秒钟后,您可以发送SIGKILL
。阅读signal(7)和signal-safety(7)。在多线程但特定于Linux的程序中,您可以使用signalfd(2)或pipe(7)进行自欺骗(在Qt文档中为explained,但不是Qt特定)。
如果您的Linux系统是基于systemd的,则可以想象您的 program-A 是使用 systemd 工具启动的。然后,您将使用systemd工具与之“通信”。在某些方面(我不知道细节),systemd使得signals几乎过时了。请注意,信号不是多线程友好的,并且在上个世纪已经针对单线程进程进行了设计。
我们猜测通过监视器/ proc /检查运行状态的方法不正确。
检测进程是否存在(您具有足够的特权,例如,与uid / gid一起运行)的通常的方法(并且足够快,并且是“原子的”)是将kill(2)与信号号(kill
的第二个参数)为0。引用该联机帮助页:
If sig is 0, then no signal is sent, but existence and permission
checks are still performed; this can be used to check for the
existence of a process ID or process group ID that the caller is
permitted to signal.
当然,该其他进程仍然可以在与它进行任何进一步的交互之前终止。因为Linux具有抢先式调度功能。
您的看门狗进程最好使用kill(
pid-of-process-A , 0)
检查该 process-A 的存在和活跃性。使用/proc/
pid-of-process-A /
并不是正确的方法。
无论您编写什么代码,该 process-A 都可能异步消失(特别是,如果它存在导致分段错误的错误)。当进程终止时(即使出现分段错误),内核对其文件锁起作用(并“释放”它们)。
答案 1 :(得分:2)
不要扫描/proc/PID
来确定特定进程是否已终止。有很多更好的方法可以做到这一点,例如让您的看门狗程序实际启动服务器程序并等待其终止。
或者,让看门狗在TCP套接字上侦听,并使服务器进程连接到该套接字并发送其PID。如果任一端死亡,则另一端可以注意到连接已关闭(提示:每隔一段时间向心动的对等方发送心跳数据包)。如果看门狗在另一个服务器仍在运行时从另一个服务器接收到连接,则它可以决定允许它或告诉其中一个实例关闭(通过TCP或kill()
)。