1

为什么对 processEvents 的调用会阻止长达 9 秒的无操作?

我有一个带有基于 PySide 的 QT 接口的应用程序,其中 UI 代码作为较低级别的实际应用程序逻辑上的解耦层。当用户执行一个执行可能会运行一段时间的较低级别应用程序逻辑的操作时,实际上会发生以下情况:

  1. 直接在 GUI 线程上显示一个进度对话框。
  2. 直接在 GUI 线程上,较低级别的逻辑启动一个工作线程。
  3. 直接在 GUI 线程上,较低级别的逻辑循环更新进度对话框(间接/解耦)并通过 QtGui.qApp.processEvents() 标记应用程序事件队列(再次间接/解耦)。
  4. 在工作线程上,QT 函数被调用(再次间接/解耦)以响应事件,这些通过槽/信号发生在 GUI 线程上,当 GUI 线程(如上所述)调用 processEvents() 时运行。
  5. 直接在 GUI 线程上,在循环退出之前,最后一个 processEvents() 调用会阻塞大约 9 秒。这是在工作线程上的所有逻辑都结束并完成之后,并且没有更多的函数等待通过信号/插槽调用在其上运行。此调用中没有发生与我的应用程序相关的任何内容。它在那里做什么?为什么会阻塞?我尝试传入 300 毫秒的最大处理时间并查看它是否退出,但这没有什么区别。只要它愿意,呼叫就会锁定。
  6. 进度对话框关闭,用户重新获得焦点。

这都分布在许多文件中,以解耦的方式实现。我将尝试提供片段来展示流程。

解耦的低层逻辑工作循环:

    while not completed_event.wait(0.1) and not work_state.is_cancelled():
        work_completeness, work_description = work_state.get_completeness(), work_state.get_description()
        for client in self.clients:
            if work_completeness != last_completeness or work_description != last_description:
                client.event_prolonged_action_update(client is acting_client, work_description, step_count * work_completeness)
            # THE LAST CALL TO THE NEXT LINE LOCKS UP FOR NO REASON
            client.event_tick(client is acting_client)
        last_completeness, last_description = work_completeness, work_description

PySide/QT层客户端event_tick函数:

def event_tick(self, active_client):
    # THIS IS WHERE THE LOCK UP HAPPENS
    QtGui.qApp.processEvents()

PySide/QT 层中的信号/槽使用,以在 GUI 线程上发生工作线程调用:

def event_pre_line_change(self, active_client, line0, line_count):
    self.pre_line_change_signal.emit((line0, line_count))

def event_post_line_change(self, active_client, line0, line_count):
    self.post_line_change_signal.emit((line0, line_count))

def event_uncertain_reference_modification(self, active_client, data_type_from, data_type_to, address, length):
    self.uncertain_reference_modification_signal.emit((data_type_from, data_type_to, address, length))

我使用信号/插槽将工作线程上的调用委托给 GUI 线程的原因是,这是 PySide/QT 需要的,因为它们将更新 UI。

如果您想更深入地挖掘复制案例:

  • 根据 GitHub 项目自述文本下载并运行代码。
  • 从 mega下载测试文件“NEURO”(<200KB)(抱歉,这是最容易上传的网站)。
  • 在 PeaSauce 中加载 NEURO。
  • 转到偏移量 0x1A19E (CTRL-G)
  • 将数据类型更改为代码(菜单:编辑/更改地址数据类型/代码)
  • 观察进度对话框来来去去。
  • 观察~9 秒锁定。
4

0 回答 0