我有一些代码使用了 fork()
,在子进程中调用了 setsid()
,并开始一些处理过程。如果任何一个子进程退出 (waitpid(-1, 0)
),我将结束所有子进程组:
child_pids = []
for child_func in child_functions:
pid = fork()
if pid == 0:
setsid()
child_func()
exit()
else:
child_pids.append(pid)
waitpid(-1, 0)
for child_pid in child_pids:
try:
killpg(child_pid, SIGTERM)
except OSError as e:
if e.errno != 3: # 3 == no such process
print "Error killing %s: %s" %(child_pid, e)
然而,有时调用killpg
会失败并显示“操作不允许”的错误信息:
无法终止22841号进程:[Errno 1] Operation not permitted
为什么会出现这种情况呢?
下面是一个完整的可运行示例:
from signal import SIGTERM from sys import exit from time import sleep from os import *
def slow(): fork() sleep(10)
def fast(): sleep(1)
child_pids = [] for child_func in [fast, slow, slow, fast]: pid = fork() if pid == 0: setsid() child_func() exit(0) else: child_pids.append(pid)
waitpid(-1, 0) for child_pid in child_pids: try: killpg(child_pid, SIGTERM) except OSError as e: print "无法终止%s号进程:%s" %(child_pid, e)
结果如下:
$ python killpg.py 无法终止23293号进程:[Errno 3] No such process 无法终止23296号进程:[Errno 1] Operation not permitted
killpg
有更复杂的权限规则。此外,即使你无法使用killpg
命令,你能否使用kill
命令来终止子进程?(我知道这不是解决方案,只是为了帮助诊断问题。) - abarnertwaitpid
使其极不可能发生):没有强制要求在调用killpg
之前完成setsid
。通常避免这种竞态条件的方法是在子进程和父进程中都设置进程组,但这样会阻止setsid
,因此你可能需要使用显式同步。 - jilles