流程后代


20

我正在尝试建立一个过程容器。该容器将触发其他程序。例如-一个bash脚本,它以'&'用法启动正在运行的后台任务。

我所追求的重要功能是:杀死容器时,应该杀死所有在其下产生的东西。不仅是直系子女,还有他们的后代。

当我开始这个项目时,我错误地认为,当您杀死一个进程时,它的孩子也会被自动杀死。我已经从有同样错误想法的人那里寻求建议。尽管可以捕捉到信号并将杀人事件传递给孩子,但这并不是我在这里寻找的东西。

我相信我想要实现的目标,因为当您关闭xterm时,其中运行的所有内容都会被杀死,除非未进行任何操作。这包括孤立的过程。那就是我想要重新创建的东西。

我有一个想法,就是我所寻找的是unix会话。

如果有一种可靠的方法来标识一个进程的所有后代,那么也能够向他们发送任意信号将很有用。例如SIGUSR1。


好吧,杀死父进程将SIGHUP其直接子进程发送给它。挂断信号的默认处理程序中止进程执行,因此默认路由是杀死所有后代。阅读有关流程和流程组的更多信息。
亚历克斯

关闭xterm会杀死xterm中产生的所有内容,因为TTY被破坏了。如果您想出一种创建可以供子进程使用的tty的方法,则可以销毁TTY并完成相同的操作。任何没有关闭该TTY的进程(nohup和朋友)都将得到SIGHUP。
Patrick

Answers:


23

如果您向某个进程发送信号,该进程将被杀死。我不知道谣言说杀死一个进程也会杀死其他进程,这似乎是特别违反直觉的。

但是,有多种方法可以杀死多个进程。但是您不会向一个进程发送信号。您可以通过向-1234发送信号来杀死整个进程组,其中1234是PGID(进程组ID),它是进程组负责人的PID。当您运行管道时,整个管道作为一个进程组开始(应用程序可以通过调用setpgid或来更改它setpgrp)。

在后台启动进程(foo &)时,它们位于自己的进程组中。进程组用于管理对终端的访问;通常只有前台进程组才能访问终端。后台作业保留在同一会话中,但是没有任何功能可以终止整个会话,甚至无法枚举会话中的进程组或进程,因此这无济于事。

当您关闭一个终端时,内核会将信号发送SIGHUP到所有以其为控制终端的进程。这些进程形成一个会话,但并非所有会话都具有控制终端。因此,对于您的项目,一种可能性是在由脚本屏幕等创建的自己的终端中启动所有进程。终止终端仿真器进程以终止所包含的进程(假设它们尚未与割裂setsid)。

您可以通过以自己的用户身份运行进程来提供更多隔离,该用户不执行任何其他操作。然后,杀死所有进程很容易:以该用户身份运行kill系统调用实用程序),并使用-1作为PID参数杀死,这意味着“该用户的所有进程”。

通过在实际容器中运行所包含的进程,您可以提供更多的隔离,但设置要多得多。


如果您对自己的进程进行编程,则可以使用诸如:prctl(PR_SET_PDEATHSIG, SIGHUP);,更多信息:man7.org/linux/man-pages/man2/prctl.2.html
Alexis Wilke

吉尔斯(Gilles),您提到了这一点-“关闭终端时,内核会将信号SIGHUP发送到将其作为控制终端的所有进程”。从这个我surmising终端发送SIGHUP到会话组长(壳)谁转发到会话中的所有进程组。两者中的哪一个是正确的?
iruvar

4

在父脚本中捕获杀死信号,并使其杀死所有子代。例如,

#!/bin/bash
# kill the parent and children together
trap "kill 0" EXIT
# create all the children
for n in $(seq 1 100)
do
    ( echo "begin $n"; sleep 60; echo "end $n" ) &
done
# wait for the children to complete
wait

2

识别进程的所有后代的可靠方法是使用以下命令pstree <pid>,其中pid是您的父进程ID。

pstree 此处阅读手册页。

通知进程组的所有成员:killpg(<pgrp>, <sig>);
其中pgrp是进程组号,而sig是信号。

要等待指定进程组中的子进程: waitpid(-<pgrp>, &status, ...);

您正在执行的另一种选择是在新的bash shell中运行过程容器。使用命令创建新的bash shell,bash然后运行您的进程。当您要结束所有进程时,请使用命令退出外壳程序exit


我认为killpg将允许我做我需要做的事情。谢谢。
Craig Turner

1

采用

unshare -fp --kill-child -- yourprogram

如果您杀死unshare,则所有子进程(yourprogram可能已生成)都将被杀死。

现在可以通过util-linux来实现2.32我在上游实现了这一点。它需要用户名称空间(内核配置选项CONFIG_USER_NS=y)或root特权。另请参阅此处


0

pslist软件包中的rkill命令将给定信号(SIGTERM默认情况下)发送到指定的进程及其所有后代:

rkill [-SIG] pid/name...

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.