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

Rui*_*lho 5 python windows multiprocessing

在 Windows 上使用 python 3.4。
我正在尝试终止模拟一个人按 Ctrl+C(在 linux 上为 Ctrl+D)的子进程。

我只是添加了处理程序来检查信号是否正在被处理。我使用了这个问题的想法

目标是捕获 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")
Run Code Online (Sandbox Code Playgroud)

下面是一个输出示例:

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

dan*_*ano 5

它不起作用,因为你不能使用它os.kill在 Windows 上发送任意信号:

os.kill(pid, sig)

向进程 pid 发送信号 sig。主机平台上可用的特定信号的常量在信号模块中定义。

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

唯一可以通过 和 发送os.killsignal.CTRL_C_EVENT信号signal.CTRL_BREAK_EVENT。其他任何事情都会终止该过程,这就是您的情况所发生的情况。使用signal.CTRL_C_EVENT在这里也不起作用,因为通过启动的进程multiprocessing.Process不是“与父级共享公共控制台窗口的控制台进程” 。我不确定 Windows 上的信号能做多少事情;看起来您不被允许以在 Unix 上TerminateProcess捕获的方式捕获SIGTERM,因此您无法在进程终止之前进行任何清理,并且您没有为子进程使用控制台应用程序,所以signal.*_EVENT赢了不工作。

我认为您的选择是:1)使用该subprocess模块,并使用 启动子进程shell=True,我相信这意味着signal.CTRL+C+EVENT会起作用。2)坚持使用multiprocessing模块,并使用“合作”方法来中断工作人员,例如multiprocessing.Event