我有一个程序可以fork()
和exec()
链中的多个进程。
例如:过程A - >; fork,exec B - > fork,exec C - > fork,exec D.所以A是C的曾祖父母。
现在的问题是我对进程B,C和D没有任何控制权。因此,可能会发生一些事情。
setsid()
更改其进程组和会话。 因此,我不能依赖进程组ID或父ID来跟踪A的所有后代。是否有任何可靠的方法来跟踪所有后代?更具体地说,我想杀死所有的后代(孤儿和其他)。
如果符合POSIX标准,也会很棒。
答案 0 :(得分:4)
POSIX方法只是使用进程组。明确改变其进程组/会话的后代进程正在做出故意决定而不是让他们的生命周期跟踪他们的原始父 - 他们特别是从父母的控制中解放自己。这些过程不是孤儿 - 他们是成年人“飞过巢穴”并希望控制自己的一生。
答案 1 :(得分:2)
我同意caf的一般情绪:如果一个过程调用setsid
,它就说它想要独立生存,无论如何。你需要仔细考虑是否真的要杀死它们。
话虽如此,有时候,你会想要某种形式的“超级会话”来包含一个进程树。在POSIX工具箱中没有提供此类超级会话的工具,但我将提出一些解决方案。每种解决方案都有其自身的局限性,因此很可能它们并非都适用于您的案例,但希望其中一种适用。
一个干净的解决方案是在自己的虚拟化环境中运行流程。这可能是FreeBSD风格的jail,Linux cgroups或任何其他类型的虚拟化技术。这种方法的局限性在于虚拟化技术依赖于操作系统,而且这些过程将在不同的环境中运行。
如果您在系统上只有这些进程的单个实例,并且可以涉及到root,请以专用用户身份运行这些进程。超级会话被定义为作为专用用户运行的进程。使用kill(-1, signum)
杀死后代(请注意,这将杀死杀手进程本身,除非它被阻止或处理信号)。
您可以使进程打开一个唯一文件,确保在文件描述符上设置了FD_CLOEXEC
标志。然后,除非在调用FD_CLOEXEC
之前显式删除execve
标志或关闭文件,否则所有子进程都将继承打开的文件。使用fuser -k
或使用fuser
或lsof
(fuser
在POSIX中,但不是fuser -k
获取流程ID列表来杀死流程。)请注意有一个竞争条件:一个过程可能在你调用fuser
的时间和你杀死它的时间之间分配;因此,您需要在循环中调用fuser
,直到不再出现进程(在所有进程都死之前不要循环,因为如果其中一个进程阻塞了您的信号,这可能是无限循环)。
您可以生成唯一的随机字符串,并使用该名称或使用已知名称和该唯一字符串作为值来定义环境变量。它将由所有后代进程继承,除非他们选择更改其环境。没有可移植的方法来根据环境搜索进程,甚至无法获取其他进程的环境。在许多unix变体上,您可以通过ps
选项获取信息(例如* BSD上的ps -e
或Linux上的ps e
;信息可能不容易解析,但唯一字符串的存在是一个充分的指标。与上面的fuser
一样,请注意如果后代调用fork
为时太晚而无法注意到其子项但在您可以杀死父级之前需要循环来避免竞争条件。
您可以LD_PRELOAD
一个小型库,它可以分支在通信通道上侦听的线程,并在收到通知后终止其进程。如果它希望了解所有自己的线程,这可能会中断该过程;它只适用于标准库始终是线程安全的体系结构,并且您将错过静态链接的进程。通信信道可以是允许主进程广播自杀命令的任何信息;一种可能性是一个管道,其中每个后代进程执行阻塞读取,并且祖先进程关闭管道以通知后代。通过环境变量传递文件描述符号。