嵌套的 DirectConnection 信号导致段错误

Posted

技术标签:

【中文标题】嵌套的 DirectConnection 信号导致段错误【英文标题】:Nested DirectConnection Signals are causing a segfault 【发布时间】:2014-12-29 14:38:07 【问题描述】:

这是我的unanswered question here 的后续行动。代码,正如它下面的那样,因段错误而崩溃(将其复制/粘贴到您的系统中并运行它)。当我从一个或两个信号构造函数调用中删除type=QtCore.Qt.DirectConnection 时(因此使用QtCore.Qt.AutoConnection 代替),一切都按照它应该的方式运行:出现一个小部件,显示五个进度条填满然后在无限循环中清空。

from PySide import QtCore, QtGui
import time

class Worker(QtCore.QThread):
    sig_worker_update_progress = QtCore.Signal(int, int)

    def __init__(self, thread_id, *args, **kwargs):
        super(Worker, self).__init__(*args, **kwargs)
        self.thread_id = thread_id
        self.stop_requested = False

    def slot_interrupt(self):
        self.stop_requested = True

    def run(self):
        progress = 0
        while(True):
            self.sig_worker_update_progress.emit(self.thread_id, progress % 100)
            progress += 1
            if self.stop_requested:
                break
            else:
                time.sleep(0.1)


class Controller(QtCore.QObject):
    sig_controller_update_progress = QtCore.Signal(int, int)

    def __init__(self, num_workers, *args, **kwargs):
        super(Controller, self).__init__(*args, **kwargs)

        self.workers = []
        for i in range(num_workers):
            self.workers.append(Worker(i))
            self.workers[i].sig_worker_update_progress.connect(
                self.slot_worker_update_progress,
                type=QtCore.Qt.DirectConnection)
        for worker in self.workers:
            worker.start()

    def slot_worker_update_progress(self, thread_id, progress):
        # Do
        # Stuff
        self.sig_controller_update_progress.emit(thread_id, progress)


class Monitor(QtGui.QWidget):
    def __init__(self, num_workers, *args, **kwargs):
        super(Monitor, self).__init__(*args, **kwargs)
        main_layout = QtGui.QVBoxLayout()
        self.setLayout(main_layout)
        self.progress_bars = []

        for _ in range(num_workers):
            progress_bar = QtGui.QProgressBar()
            main_layout.addWidget(progress_bar)
            self.progress_bars.append(progress_bar)

        self.controller  = Controller(num_workers)
        self.controller.sig_controller_update_progress.connect(
            self.slot_controller_update_progress,
            type=QtCore.Qt.DirectConnection)

    def slot_controller_update_progress(self, thread_id, progress):
        self.progress_bars[thread_id].setValue(progress)


if __name__ == "__main__":
    app = QtGui.QApplication([])
    monitor = Monitor(5)
    monitor.show()
    app.exec_()

为什么使用两个嵌套的DirectConnection 信号会导致段错误?如果 Qt 不希望您这样做,为什么没有给出更多信息的错误?

我正在使用封装了 Qt 4.8 框架的 PySide v1.2.2。

【问题讨论】:

回溯中到底是什么?尝试获取二进制文件的调试版本以正确查看。 【参考方案1】:

我找到了一个令人满意的解释here。显然,发出DirectConnection 类型的信号相当于直接调用函数。因此,当两个信号都是DirectConnect-ed 时,GUI 最终会在Worker 线程上更新。正如我的other question 中提到的,线程不允许更改 GUI。问题不在于嵌套 DirectConnections 本身。

【讨论】:

附带说明:除非在非常特殊的情况下或进行大量优化时,否则可能永远不需要将连接类型从 AutoConnection 更改为 DirectConnection。所以可能永远不会。 请参阅 here 了解我为什么需要使用 DirectConnections 的背景。

以上是关于嵌套的 DirectConnection 信号导致段错误的主要内容,如果未能解决你的问题,请参考以下文章

Qt 信号(QueuedConnection 和 DirectConnection)

Qt::浅谈信号槽连接,参数在多线程中的使用

qt多线程信号槽传输方式

在 QObject 之间跨不同线程连接信号/插槽

Qt::ConnectionType(信号与槽的传递方式)

使用嵌套异步调用锁定