【问题标题】:How to properly exit from Pyside2 multi-thread GUI application?如何正确退出 Pyside2 多线程 GUI 应用程序?
【发布时间】:2021-01-09 14:28:42
【问题描述】:

我正在使用 pyside2 并编写了一个应用程序,其中有几个线程使用队列在它们之间进行通信。一个线程从串行端口读取数据并将数据传递给另一个线程,该线程解析它们并在绘图之前进行一些计算。从我的 app_main.py 文件中:

import sys
# omissis various import statements

class MainWindow(QMainWindow, Ui_MainWindow):
    serialRxQu = Queue()  # serial FIFO RX Queue
    serialWo = ""

    def __init__(self, *args, **kwargs):
        Ui_MainWindow.__init__(self)
        QMainWindow.__init__(self)
        # omissis, various ui initializations

         # Visualization Worker Thread, started as soon as the thread pool is started.
        self.viewWo = ViewWorker(self.serialRxQu, self.canvas, self.textEdit)
        # serial Worker Thread started later
        self.serialWo = SerialWorker(self.serialRxQu, self.textEdit)

        self.threadpool = QThreadPool()
        self.threadpool.start(self.viewWo)


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())

我省略了一些对问题无用的部分,如果不包含其他文件,它们将难以解释。

应用程序 exec 是使用 `sys.exit(app.exec_()) 调用的,据我了解,这意味着当我关闭应用程序的主窗口时,事件调度程序将关闭并传递返回代码到 sys.exit 应该终止应用程序的执行。

我尝试使用命令python app_main.py 从 Windows 中的命令行启动应用程序,我看到的是,当我关闭应用程序的主窗口时,进程似乎挂在终端中,我从来没有得到提示返回。
我还尝试将sys.exit()app.exec_() 分开,如下所示:

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    style_man = StyleManager(app)
    window = MainWindow()
    window.show()
    # sys.exit(app.exec_())
    app.exec_()
    print("I pass here!")
    sys.exit(0)

我在终端上看到了 I pass here! 的打印字样,但在这种情况下,我再也没有收到提示。我确实希望sys.exit() 调用会终止进程,但也许有一些东西挂起并阻止应用程序关闭?
可能是事件调度程序仍在运行吗?或者任何与线程或队列相关的东西?
还是我应该使用不同于sys.exit() 的东西?

我希望能正确解释我的情况和我的疑问,否则我会尝试纠正我的问题。

【问题讨论】:

    标签: python multithreading exit pyside2


    【解决方案1】:

    经过一些故障排除后,我认为我发现了我的程序的问题。

    对于线程,我使用从 QRunnable 派生的对象,线程是无限循环,一个监听串行,另一个在新数据到达时绘制数据。

    作为无限循环,线程继续运行,并且由于它们每个人都有一个计时器对象,因此计时器对象可能会阻止执行调度程序终止。

    为了解决这个问题,我在线程循环中添加了一个标志并使用了应用程序的关闭事件

        def closeEvent(self, event):
            self.set_finish_signal()
            app.exit(0)
    
        def set_finish_signal(self):
            self.viewWo.terminate_thread()
            self.serialWo.terminate_thread()
    

    运行循环条件在启动时始终为 False,terminate_thread 函数将信号更改为 True 并且 Run 终止,释放计时器资源并允许执行正确终止。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-02-09
      • 1970-01-01
      • 2023-03-10
      • 2012-10-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多