发送给子进程的CTRL_C_EVENT杀死父进程

时间:2019-10-18 17:34:35

标签: python windows python-2.7 python-multiprocessing

我正在编写一个并行运行后台进程的脚本。重新启动脚本时,我希望能够通过发送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异常,但是第二次调用该函数时会触发该异常。为什么会这样?

1 个答案:

答案 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()
相关问题