在UNIX系统中,如何使用C/C++编写程序来终止父进程的所有子进程?

3

我有一个函数,它的输入参数是进程ID(PID)。

例如:

bool KillProcessTree (int ParentPID)
{

}

现在我想写上面函数的定义,它首先会获取所有子进程然后杀死它们。
Unix中是否有任何API可以使用父进程PID并返回父进程创建的子进程数量?

1
对于Linux系统,killpg系统调用可能会很有用。或者,使用kill,并设置pid = -1 - Brett Hale
请查看以下链接:https://dev59.com/zXbZa4cB1Zd3GeqPBxdQ - Hayri Uğur Koltuk
@BrettHale 确实很有用,但父子关系与进程组关系相当不同。 - WGH
将kill(ParentPID, SIGKILL)会杀死所有父进程的子进程吗? SIGKILL的定义如下。 SIGKILL - 最强大的终止信号,立即结束一个进程,并且不能被程序阻塞或处理。 - user3253461
@user3253461 选择信号与选择进程无关。KILL命令结束了一个进程,不能被处理或阻塞,但你结束的是那个特定的进程,而不是其他任何进程。 - Gilles 'SO- stop being evil'
2个回答

3

没有标准的Unix API可以检索给定进程的子进程列表。

您可以列出系统上所有进程及其父进程,并从中构建进程树。这样做的可移植方式是运行以下命令:

ps -e -o ppid= -o pid=

并解析输出(popenscanf("%ld %ld\n")的循环将起作用)。将数据存储为从PPID到PID的有限映射,然后遍历树以收集您感兴趣的进程的后代列表。

如果任何一个进程在处理过程中分叉或退出,则可能会错过它。如果运气不好,进程可能会退出,并且其PID可能在您执行所有此操作时得到重用。此外,如果进程P分叉出子进程Q,Q再分叉出孙子R,然后Q退出,R的PPID将设置为1,因此您将无法检测到R最初是P的后代。

简而言之:无论您的问题是什么,这很可能是错误的方法。

Unix具有处理此问题的功能:进程组。很可能进程组是您试图解决问题的答案。您可以使用kill(-pgid,signal_number)原子地向进程组中的所有进程发送信号signal_number

您应该安排所有要杀死的进程属于同一进程组,并且不希望杀死的进程不属于该进程组。使父进程调用setsidsetpgid,然后杀死该进程组。


谢谢,这个回答真的很有帮助。但是使用popen()和命令“ps -e -o ppid= -o pid=”,我能获取所有子进程和孙子进程吗? - user3253461
@user3253461,您可以获取系统上的所有进程,并需要过滤该列表以提取您想要的进程。 - Gilles 'SO- stop being evil'
我不熟悉 signum。它只是 "signal number"的简写,还是一些我在 man signal.h 中找不到的花哨信号? - lindhe
@lindhe 只是“信号编号”的简写。 - Gilles 'SO- stop being evil'

1
我会简单地在fork()时将所有子pid存储在父进程的pid_t数组中。之后,通过循环该数组来杀死所有子进程。
pid_t all_child[10]; // you should not define a fixed length array, you can use pointer.
if((pid = fork()) == 0)
{
     //child processes
}
else
{
//parent process
all_pid[counter] = pid;
}

当杀死时,

for( i = 0; i < counter; i++)
{
kill(all_pid[i], SIGTERM);
}

2
只有当您的代码作为父进程运行时才有效。问题并没有包含这个假设。 - WGH
@WGH 当然我同意你的观点,在杀死父进程的所有子进程的情况下,我会回答。但是我不确定是否有一个函数可以通过给定父进程pid来收集所有子进程的pid。很高兴听到这个消息。 - pmverma
1
没有。你可能需要循环遍历依赖于操作系统的表,例如Linux上的procfs,以查找子进程,但是这不具有可移植性并且容易受到竞态条件的影响。 - WGH

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接