Search code examples
pyqtqthread

Pyqt5 Two QThread communicate use signal and slot issue


I'm trying to use the pyqt qthread for multithreading program.

In the code, there are two different workers instance. I try to use signal and slot for data share. but it seemed that the signal is blocked until one of the qthread is finished.

this is the code.

from PyQt5.QtCore import QCoreApplication,QThread, QObject, pyqtSignal, pyqtSlot
import time
import sys

class Worker(QObject):
    finished = pyqtSignal()
    intReady = pyqtSignal(int)

    @pyqtSlot()
    def work(self):  # A slot takes no params
        for i in range(1, 10):
            time.sleep(1)
            self.intReady.emit(i)

        self.finished.emit()


class Worker2(QObject):
    finished = pyqtSignal()
    intReady = pyqtSignal(int)

    @pyqtSlot()
    def work(self):  # A slot takes no params
        for i in range(1, 10):
            time.sleep(1)
            self.intReady.emit(i)

        self.finished.emit()

    @pyqtSlot(int)
    def revsignal(self, val):
        print("hello rev a signal"+str(val))

def updateLabel(val):
    print("updateLable "+str(val))

app = QCoreApplication(sys.argv)
# 1 - create Worker and Thread inside the Form
worker = Worker()  # no parent!
thread = QThread()  # no parent!

worker2 = Worker2()
thread2 = QThread()

worker.intReady.connect(updateLabel)
worker.intReady.connect(worker2.revsignal)

worker.moveToThread(thread)
worker.finished.connect(thread.quit)
thread.started.connect(worker.work)
# self.thread.finished.connect(app.exit)


worker2.moveToThread(thread2)
worker2.finished.connect(thread2.quit)
thread2.started.connect(worker2.work)

thread2.finished.connect(app.exit)



thread2.start()
print("after thread2 start")
thread.start()
print("after thread1 start.")



sys.exit(app.exec_())

and the output is here

after thread2 start
after thread1 start.
updateLable 1
updateLable 2
updateLable 3
updateLable 4
updateLable 5
updateLable 6
updateLable 7
updateLable 8
updateLable 9
hello rev a signal1
hello rev a signal2
hello rev a signal3
hello rev a signal4
hello rev a signal5
hello rev a signal6
hello rev a signal7
hello rev a signal8
hello rev a signal9

Process finished with exit code 0

i don't know why the worker2 thread can't receive the signal as soon as the work1 emit the signal. until the work1 thread ended.

Any help is greatly appreciated!


Solution

  • First thing is that all slots should be members of a class which inherits from QObject. So make a class like this

    class Manager(QObject):
        @pyqtSlot(int)
        def updateLabel(self, val):
            print("updateLable "+str(val))
    manager = Manager()
    

    Next, as per the docs here, there is an additional argument which can be passed to connect to control the behavior of cross-thread signal processing. You need to change three lines.

    from PyQt5.QtCore import QCoreApplication, QThread, QObject, pyqtSignal, pyqtSlot, Qt
    

    to get the Qt namespace, and both of

    worker.intReady.connect(manager.updateLabel, type=Qt.DirectConnection)
    worker.intReady.connect(worker2.revsignal, type=Qt.DirectConnection)
    

    to set the connection type.