使用os.kill将SIGINT发送到Python子进程,就像按Ctrl + C一样

时间:2014-10-26 22:40:59

标签: python windows multiprocessing

在Windows上使用python 3.4 我试图终止一个孩子处理模拟一个人按Ctrl + C(Linux上的Ctrl + D)。

我刚刚添加了处理程序以检查信号是否正在处理。 I used the idea from this question

目标是捕获KeyboardInterrupt(SIGINT),并释放资源。但是,如果SIGINT不是来自键盘,似乎不会抛出异常。这就是为什么我创建了一个处理程序,但这个过程似乎根本不运行处理程序......

import multiprocessing
import time
import signal
import signal
import os
import sys

def handler(signal, frame):
    print("handler!!!")
    sys.exit(10)

def worker(): 
    p = multiprocessing.current_process()
    try:
        signal.signal(signal.SIGINT,handler)  
        print("[PID:{}] acquiring resources".format(p.pid))
        while(True):           
            #working...
            time.sleep(0.5)
    except (KeyboardInterrupt, SystemExit):
        pass
    finally:
        print("[PID:{}] releasing resources".format(p.pid))

if __name__ == "__main__":
    lst = []
    for i in range(1):
        p = multiprocessing.Process(target=worker)
        p.start()
        lst.append(p)

    time.sleep(3)      
    for p in lst:        
        os.kill(p.pid,signal.SIGINT)
        p.join()
        print(p)
        print(p.exitcode)
    print("joined all processes")

以下是输出示例:

C:\Users\Rui>python test.py
[PID:16524] acquiring resources
<Process(Process-1, stopped[2])>
2
joined all processes
  • 我做错了什么?
  • 我应该使用子进程模块吗?
  • 我可以尝试其他哪些方法来中断流程执行?

1 个答案:

答案 0 :(得分:1)

它无效,因为您无法使用os.kill在Windows上发送任意信号:

  

<强> os.kill(pid, sig)

     

将信号sig发送到进程pid。特定信号的常数   主机平台上提供的信息在信号模块中定义。

     

Windows:signal.CTRL_C_EVENTsignal.CTRL_BREAK_EVENT信号   是特殊信号,只能发送到控制台进程   共享公共控制台窗口,例如一些子过程。 任何其他   sig的值将导致进程无条件地被杀死   TerminateProcess API,退出代码将设置为sig 。该   Windows版本的kill()还需要进程句柄   杀死。

可以通过os.kill发送的唯一信号是signal.CTRL_C_EVENTsignal.CTRL_BREAK_EVENT。其他任何事情都会终止这个过程,这就是你的情况。使用signal.CTRL_C_EVENT也不会在这里工作,因为通过multiprocessing.Process启动的进程不是“控制台进程,它与父进程共享一个公共控制台窗口”。我不确定你能在这里用Windows上的信号做多少事情;看起来你不能以TerminateProcess的方式捕获SIGTERM在Unix上捕获signal.*_EVENT的方式,因此在进程终止之前你不能进行任何清理,而你不是为孩子使用控制台应用程序,因此subprocess将无效。

我认为您的选择是:1)使用shell=True模块,并使用signal.CTRL+C+EVENT启动子进程,我相信multiprocessing将起作用。 2)坚持{{1}}模块,并使用“合作”方法打断工作人员,如multiprocessing.Event