QTimer в графическом интерфейсе блокировки рабочего потока

Я пытаюсь создать рабочий поток, задачей которого является отслеживание бита состояния платформы позиционирования.

Для этого я подключаю сигнал тайм-аута QTimer к функции, которая запрашивает платформу.

class expSignals(QtCore.QObject):
    pause=QtCore.pyqtSignal()

class motorpositioner(QtCore.QObject):
def __init__(self):
    QtCore.QThread.__init__(self)
    self.timer = QtCore.QTimer()
    self.timer.start(100)
    self.timer.timeout.connect(self.do_it)
    self.lock=QtCore.QMutex()
    self.running=True
    self.stat=0
def do_it(self):
        with QtCore.QMutexLocker(self.lock):
            #self.stat = self.motors.get_status()
            print(self.stat)
        time.sleep(5)
@QtCore.pyqtSlot()
def stop1(self):
    self.timer.stop()
    print('stop heard')

Материал GUI выглядит следующим образом:

class MyApp(QtWidgets.QMainWindow):
    def __init__(self):
        QtWidgets.QMainWindow.__init__(self)
        self.thread=QtCore.QThread(self)
        #worker
        self.mot=motorpositioner()

# =============================================================================
#         Putting buttons and GUI stuff in place
# =============================================================================
        self.button=QtWidgets.QPushButton('Derp',self)
        layout = QtWidgets.QHBoxLayout()
        layout.addWidget(self.button)
        self.setLayout(layout)
        self.setGeometry( 300, 300, 350, 300 )

# =============================================================================
#         Connecting signals
# =============================================================================

        self.sig=expSignals()
        self.sig2=expSignals()
        self.button.clicked.connect(self.stop)
        self.sig.pause.connect(self.mot.stop1)
        self.sig2.pause.connect(self.thread.quit)


        self.mot.moveToThread(self.thread)
        self.thread.start()
    def stop(self):
        self.sig.pause.emit()

    def closeEvent(self,event):
        self.sig2.pause.emit()
        event.accept()

Однако, как это написано сейчас, графический интерфейс не отвечает. Однако, если я закомментирую self.timer.timeout.connect(self.do_it) и поставлю do_it в цикл while(True), графический интерфейс не будет заблокирован.

Почему основной поток блокируется при использовании QTimer?


person Jānis Šmits    schedule 12.07.2018    source источник
comment
что такое expSignals?   -  person eyllanesc    schedule 12.07.2018
comment
сестренка, почему я удивлен, что вы использовали QTimer вместо потоковой передачи стандартной библиотеки, которая поставляется с python. нельзя доверять фреймворку, чтобы он работал все время Пожалуйста, считайте, что это тоже нормально.   -  person surge10    schedule 12.07.2018
comment
Использование потоков QTimer и QT, следуя совету из этого поста: ">ссылка. Также не уверен, как справиться с двумя типами подходов к многопоточности, поскольку один из них доставляет мне достаточно много времени.   -  person Jānis Šmits    schedule 12.07.2018


Ответы (1)


Я не знаю, что такое expSignals() и думаю, что это не имеет значения, как и кнопка.

В вашем коде есть следующие ошибки:

  • Вы запускаете таймер до запуска потока, поэтому задача будет выполняться в потоке графического интерфейса.

  • QTimer не является потомком motorpositioner, поэтому, если motorpositioner перейдет в новый поток, QTimer не будет. Чтобы он мог двигаться, он должен быть сыном, поэтому вы должны передать его себе как родителя.

  • Я не знаю, настоящая ли это ошибка, но вы запускаете QTimer каждые 100 мс, но задача занимает 5 секунд, хотя QMutex помогает не иметь проблем, потому что он заблокирован.


import sys
from PyQt5 import QtCore, QtGui, QtWidgets

import time

class motorpositioner(QtCore.QObject):
    def __init__(self):
        QtCore.QThread.__init__(self)
        self.timer = QtCore.QTimer(self)

        self.lock = QtCore.QMutex()
        self.running = True
        self.stat = 0

    def start_process(self):
        self.timer.timeout.connect(self.do_it)
        self.timer.start(100)

    def do_it(self):
        with QtCore.QMutexLocker(self.lock):
            #self.stat = self.motors.get_status()
            print(self.stat)
            time.sleep(5)

    @QtCore.pyqtSlot()
    def stop1(self):
        self.timer.stop()
        print('stop heard')

class MyApp(QtWidgets.QMainWindow):
    def __init__(self):
        QtWidgets.QMainWindow.__init__(self)

        self.thread = QtCore.QThread(self)
        self.mot = motorpositioner()
        self.mot.moveToThread(self.thread)
        self.thread.started.connect(self.mot.start_process)
        self.thread.start()

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    ex = MyApp()
    ex.show()
    sys.exit(app.exec_())
person eyllanesc    schedule 12.07.2018
comment
Спасибо, перемещение таймера на ребенка помогло! Также, чтобы уточнить - была добавлена ​​​​кнопка, чтобы проверить, могу ли я остановить таймер снаружи. 5-секундный сон был преувеличением зависания графического интерфейса, поскольку я не заметил этого со 100 мс. - person Jānis Šmits; 12.07.2018