如何杀死python中的分叉子及其jackd子进程
我试图实现一个托盘图标,它可以让我控制一个进程(jackd)。最值得注意的是如何杀死python中的分叉子及其jackd子进程
- 我想读的过程输出和错误进行日志记录
- 我希望能够从主程序菜单项杀死进程
杀伤引起我头痛。我相信,当我阅读stdout和stderr时,我必须在一个额外的线程/进程中做到这一点,以保持图标的响应。所以我用fork()来创建一个子进程,并在子进程上调用setsid()
。然后,该子进程调用jackd使用subprocess
模块
from subprocess import PIPE, STDOUT, Popen
def runAndLog(self, cmd):
po = Popen(cmd, stdout=PIPE, stderr=STDOUT)
line = po.stdout.readline()
while line:
print(line.rstrip())
line = po.stdout.readline()
self.runAndLog(["jackd","-R", "-P80", "-t5000", "-dfirewire", "-r44100", "-p256", "-n3"])
现在,我希望我能得到我的派生的子进程和jackd到同一个进程组,这样我就可以同时杀死一气呵成,但让我吃惊Popen
创建一个新的进程组和一个新的会话:
PID PPID PGID SID COMMAND
5790 5788 5788 31258 python (parent, main)
5791 5790 5791 5791 python (forked child after setsid - ok)
5804 5791 5804 5804 jackd (grandchild created by Popen)
所以,造成孩子不会杀死孙子,我看不出在作出已知main
孙子的PID(5804)的任何清洁方式为了明确地杀死它。我可能会用一些信号欺骗手段让垂死的孩子杀死孙子,但我毫不犹豫地这样做。
我也不能在jackd进程上使用setpgid
来迫使它进入子进程组,因为它的SID与我孩子的SID不同。
我相信我要么
- 必须说服POPEN不是创建一个新的会话,或
- 使用一个模块与魔法小于
subprocess
,但仍alows我读输出和错误。
但我不知道该怎么做。无可否认,我对过程组的了解有限。
/home/martin >python --version
Python 2.7.1
更新10月12日
我发现新的会话不被蟒蛇创建,而是由jackd
本身。当我用xterm
替换jackd时,一切都很好。
PID PPID PGID SID COMMAND
12239 4024 12239 4024 python (parent, main)
12244 12239 12244 12244 python (forked child after setsid - ok)
12249 12244 12244 12244 xterm (grandchild has same PGID and SID - ok)
我还发现this
这些插孔天调用setsid()得到确立了其作为一个新的 工艺组组长
这只是离开选项
- 使jack的PID已知
main
和明确杀死它,或 - 有垂死的孩子杀杀人jackd
上有什么建议?
。
由于您的孙子设置了自己的会话和sid,因此您不能指望group-kill正常工作。你有三种选择:
迭代整个子进程树,并从父母开始全部杀死它们(以便它们不会重新启动孩子)。丑陋和过于复杂的解决方案。
使用主(root)进程中的线程直接控制
jack
子。中间儿童流程在这里可能没有必要,因为它没有任何好处。这是可能的最简单的解决方案。如果你还必须有中间的孩子的过程中,唯一的办法是捕捉发送到子的终止信号,并传输给孙子:
child.py
:
import signal
import subprocess
# The signal handler for the child process, which passes it further to the grandchild.
def handler(signum, frame):
print('Killing self, killing the children')
os.kill(proc.pid, signal.SIGTERM)
# wait for the process to die gracefully for N secs.
time.sleep(5)
os.kill(proc.pid, signal.SIGKILL)
cmd = ["jackd","-R", "-P80", "-t5000", "-dfirewire", "-r44100", "-p256", "-n3"]
po = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
signal.signal(signal.SIGTERM, handler)
for line in po.stdout:
print(line.rstrip())
请注意,信号处理程序在进程通信开始之前安装(行读取)。
只要你的根进程“优雅地”杀死了子进程(例如,用SIGTERM),信号就会传递给孙子,并且它也会被终止/杀死。你甚至可以扩展杀戮和等待的逻辑,并强制杀死它。
但是,请记住,如果子进程被SIGKILL杀死,那么就没有机会捕获这个信号,并且孙子将继续运行孤儿。因为SIGKILL不能被设计捕获。
此答案有帮助吗? http://*.com/a/4791612 –
这几乎是我在做什么。但是,我发现问题确实是自己而不是python。我会相应地更新我的问题。 –
为什么不直接使用线程,直接控制'jack'?为什么你要独立制作一个子进程来控制实际的命令呢?使它变得如此复杂的假设好处是什么? –