Вложенные сигналы DirectConnection вызывают segfault

Это продолжение моего вопрос без ответа здесь. Код, как показано ниже, вылетает из-за segfault (скопируйте/вставьте его в свою систему и запустите). Когда я удаляю 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 вызывает segfault? Если Qt не хочет, чтобы вы это делали, почему не выдается более информативная ошибка?

Я использую PySide v1.2.2, который обертывает структуру Qt 4.8.


person nullstellensatz    schedule 29.12.2014    source источник
comment
Что именно находится в бэктреке? Попробуйте получить отладочные версии двоичных файлов, чтобы увидеть это правильно.   -  person lpapp    schedule 29.12.2014


Ответы (1)


Я нашел удовлетворительное объяснение здесь. По-видимому, выдача сигнала типа DirectConnection эквивалентна прямому вызову функции. Таким образом, графический интерфейс в конце концов обновляется в потоке Worker, когда оба сигнала имеют DirectConnect-обработку. Как упоминалось в моем другом вопросе, потокам не разрешено изменять графический интерфейс. Проблема НЕ в вложенности DirectConnection как таковой.

person nullstellensatz    schedule 29.12.2014
comment
В качестве примечания: вероятно, никогда не потребуется изменять тип соединения с AutoConnection на DirectConnection, если только в особых случаях или при сильной оптимизации. Так что наверное никогда. - person Trilarion; 06.01.2015
comment
См. здесь для фона о том, почему мне нужно было использовать DirectConnections. - person nullstellensatz; 08.01.2015