我正在编写一个并行运行后台进程的脚本。重新启动脚本时,我希望能够通过发送CTRL_C_EVENT
信号杀死后台进程并干净地退出该进程。但是由于某种原因,将CTRL_C_EVENT
信号发送到子进程也会导致将相同的信号发送到父进程。我怀疑KeyboardInterrupt
异常在子进程得到它后并没有被主进程捕获而没有被清除。
我正在使用Python版本2.7.1,并且在Windows Server 2012上运行。
import multiprocessing
import time
import signal
import os
def backgroundProcess():
try:
while(True):
time.sleep(10)
except KeyboardInterrupt:
#exit cleanly
return
def script():
try:
print "Starting function"
#Kill all background processes
for proc in multiprocessing.active_children():
print "Killing " + str(proc) + " with PID " + str(proc.pid)
os.kill(proc.pid, signal.CTRL_C_EVENT)
print "Creating background process"
newProc = multiprocessing.Process(target=backgroundProcess)
print "Starting new background process"
newProc.start()
print "Process PID is " + str(newProc.pid)
except KeyboardInterrupt:
print "Unexpected keyboard interrupt"
def main():
script()
time.sleep(5)
script()
我希望script()
函数永远不会收到KeyboardInterrupt
异常,但是第二次调用该函数时会触发该异常。为什么会这样?
答案 0 :(得分:0)
我仍在寻找有关问题发生原因的解释,但我将在此处发布我的(尽管有些hacker)解决方法,以防其他人受到影响。由于Ctrl + C会传播到父进程(仍不能完全确定为什么会发生这种情况),因此,我将仅在异常到达时捕获该异常,而不执行任何操作。
Eryk建议使用额外的看门狗线程来处理终止额外的进程,但是对于我的应用程序,这引入了额外的复杂性,并且对于我实际上需要杀死后台进程的极少数情况似乎有些过大。在大多数情况下,应用程序中的后台进程会在完成后完全关闭自身。
我仍然对不增加太多复杂性(更多进程,线程等)的更好实现的建议持开放态度。
此处修改了代码:
import multiprocessing
import time
import signal
import os
def backgroundProcess():
try:
while(True):
time.sleep(10)
except KeyboardInterrupt:
#Exit cleanly
return
def script():
print "Starting function"
#Kill all background processes
for proc in multiprocessing.active_children():
print "Killing " + str(proc) + " with PID " + str(proc.pid)
try:
#Apparently sending a CTRL-C to the child also sends it to the parent??
os.kill(proc.pid, signal.CTRL_C_EVENT)
#Sleep until the parent receives the KeyboardInterrupt, then ignore it
time.sleep(1)
except KeyboardInterrupt:
pass
print "Creating background process"
newProc = multiprocessing.Process(target=backgroundProcess)
print "Starting new background process"
newProc.start()
print "Process PID is " + str(newProc.pid)
def main():
script()
time.sleep(5)
script()