【发布时间】:2018-03-26 19:32:23
【问题描述】:
我正在尝试实现一个托盘图标,它可以让我控制一个进程(jackd)。最值得注意的是
- 我想读取进程 stdout 和 stderr 以进行日志记录
- 我希望能够从主程序的菜单项中终止进程
杀戮让我头疼。我相信,当我阅读 stdout 和 stderr 时,我必须在额外的线程/进程中执行此操作以保持图标响应。所以我使用 fork() 创建了一个子进程并在子进程上调用了setsid()。然后该子进程使用subprocess 模块调用jackd
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"])
现在我希望我可以让我的分叉子进程进入同一个进程组,这样我就可以一次杀死两者,但令我惊讶的是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魔法更少的模块,但它仍然允许我读取标准输出和标准错误。
但我也不知道该怎么做。诚然,我对进程组的了解有些有限。
/home/martin >python --version
Python 2.7.1
10 月 12 日更新
我发现新会话不是由 python 创建的,而是由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() 将自己建立为一个新的 流程组长
只剩下选择
- 让
main知道 jack 的 PID 并明确杀死它,或者 - 让垂死的孩子杀死杰克德
对此有何建议?
.
【问题讨论】:
-
这个答案有帮助吗? stackoverflow.com/a/4791612
-
这就是我正在做的事情。但是,我发现问题实际上是jackd本身而不是python。我会相应地更新我的问题。
-
为什么不只用一个线程,直接控制
jack呢?为什么要创建一个单独的子进程来控制实际命令?让它变得如此复杂有什么好处? -
fork child 用于捕获jackd的输出。我不认为我可以在不阻塞的情况下在顶级流程中做到这一点。
-
你应该可以,只要不在主线程中。主线程应该继续做它的 UI 工作,包括。响应来自操作系统的检查。这是此类应用程序中的常见模式。
标签: python linux subprocess jack process-group