You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyQt5多进程场景下,如何从主进程向工作进程触发KeyboardInterrupt?

解决Windows下PyQt5主进程向子进程触发KeyboardInterrupt的问题

原代码的核心问题是:进程拥有独立的内存空间,主进程中抛出KeyboardInterrupt只会影响自身,无法直接传递给子进程。加上Windows系统不支持像Unix那样直接给进程发送信号,导致GUI环境下的触发逻辑失效。以下是两种可行的解决方案:

方案一:使用共享事件(Event)主动触发异常

通过multiprocessing.Event实现主进程与子进程的通信,子进程定期检查事件状态,一旦主进程触发事件就主动抛出KeyboardInterrupt。

import multiprocessing as mp
from PyQt5.QtWidgets import *
import time

def worker(interrupt_event):
    ctr = 0
    for i in range(100):
        try:
            while True:
                ctr += 1
                # 定期检查中断事件,需根据实际阻塞代码调整检查频率
                if interrupt_event.is_set():
                    raise KeyboardInterrupt
                # 模拟耗时操作,替换为你的实际业务代码
                time.sleep(0.001)
        except KeyboardInterrupt:
            print(f"当前计数器值: {ctr}")
            interrupt_event.clear()  # 重置事件,支持重复触发
            ctr = 0  # 可选:重置计数器

def on_button_clicked(interrupt_event):
    interrupt_event.set()

if __name__ == '__main__':
    mp.freeze_support()
    interrupt_event = mp.Event()
    proc = mp.Process(target=worker, args=(interrupt_event,))
    proc.start()

    app = QApplication([])
    button = QPushButton('触发中断并打印计数器')
    button.clicked.connect(lambda: on_button_clicked(interrupt_event))
    button.show()
    app.exec()

说明

  • 无需额外依赖,兼容性强,适合不需要子进程控制台的场景。
  • 若你的业务代码是完全阻塞的死循环,需要确保代码中存在可插入检查逻辑的节点(比如回调、循环间隙),否则子进程无法响应事件。

方案二:使用Windows API发送CTRL_C信号

借助pywin32库调用Windows系统API,向子进程发送CTRL_C_EVENT信号,模拟原生的KeyboardInterrupt触发。

前置准备

先安装依赖库:

pip install pywin32

代码示例

import multiprocessing as mp
from PyQt5.QtWidgets import *
import win32api
import win32con
import win32process

def worker():
    ctr = 0
    for i in range(100):
        try:
            while True:
                ctr += 1
        except KeyboardInterrupt:
            print(f"当前计数器值: {ctr}")

def on_button_clicked(proc):
    # 打开子进程句柄
    handle = win32api.OpenProcess(win32con.PROCESS_ALL_ACCESS, False, proc.pid)
    # 发送CTRL_C信号
    win32process.GenerateConsoleCtrlEvent(win32con.CTRL_C_EVENT, proc.pid)
    win32api.CloseHandle(handle)

if __name__ == '__main__':
    mp.freeze_support()
    # 创建带独立控制台的子进程,否则无法接收CTRL_C信号
    proc = mp.Process(target=worker, creationflags=mp.CREATE_NEW_CONSOLE)
    proc.start()

    app = QApplication([])
    button = QPushButton('触发中断并打印计数器')
    button.clicked.connect(lambda: on_button_clicked(proc))
    button.show()
    app.exec()

说明

  • 完全模拟原生KeyboardInterrupt触发逻辑,无需修改子进程的业务代码结构。
  • 子进程会弹出独立的控制台窗口,若需要隐藏控制台可额外调用Windows API处理。

内容的提问来源于stack exchange,提问作者ACBlue

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 13:14:55