Gigino
Gigino

Reputation: 365

Correctly display thread ID with QThread

I'm trying to correctly display the ID of a thread using QThread but I get some confusing results.

I've already read this: PyQt: Connecting a signal to a slot to start a background operation , but it covers a specific question about slot and signal. This is not the case. I'm not interested in the slot connection order, the focus is infact on understainding what part of the code is running in a specific thread.

Please consider the following code:

from PyQt5.QtCore import QObject, QThread, pyqtSignal


class Worker(QObject):
    started = pyqtSignal()
    finished = pyqtSignal()
    def __init__(self, message):
        super(Worker, self).__init__()
        self.message = message
    def process(self, message):
        i = 0
        cicle = 10000
        j = 0
        while j < 5:
            i = i + 1
            if i % cicle == 0:
                j = float(i/cicle)
                print(message, j)
        print("Worker", int(QThread.currentThread().currentThreadId()))
        self.finished.emit()

worker1 = Worker("Worker 1:")
thread1 = QThread()
thread1.started.connect(lambda: worker1.process(worker1.message))
worker1.finished.connect(thread1.quit)
worker1.finished.connect(worker1.deleteLater)
thread1.finished.connect(thread1.deleteLater)
worker1.moveToThread(thread1)
print("Main app:", int(QThread.currentThread().currentThreadId()))


thread1.start()

I get the following:

Main App: 13420
Worker 1: 1.0
Worker 1: 2.0
Worker 1: 3.0
Worker 1: 4.0
Worker 1: 5.0
Worker 13420

I'm wondering why the first and the last line show the same integer id: why if i move the worker1 in another thread i get the same result?

EDIT: I edit this qustion again to spacify (again) that the problem is not in the connection order. I've tryed this code:

class Worker(QObject):
    started = pyqtSignal()
    finished = pyqtSignal()
    def __init__(self, message):
        super(Worker, self).__init__()
        self.message = message
    def process(self, message):
        i = 0
        cicle = 10000
        j = 0
        while j < 5:
            i = i + 1
            if i % cicle == 0:
                j = float(i/cicle)
                print(message, j)
        # print(int(QThread.currentThread().currentThreadId()))
        print("Worker", int(QThread.currentThread().currentThreadId()))
        self.finished.emit()

worker1 = Worker("Worker 1:")
thread1 = QThread()
worker1.moveToThread(thread1)
print("Main app:", int(QThread.currentThread().currentThreadId()))
thread1.started.connect(lambda: worker1.process(worker1.message))
worker1.finished.connect(thread1.quit)
worker1.finished.connect(worker1.deleteLater)
thread1.finished.connect(thread1.deleteLater)

thread1.start()

with the same results.

Feel free to edit the question if not good enought for the site, and thank you for any suggestion.

Upvotes: 1

Views: 1780

Answers (2)

ekhumoro
ekhumoro

Reputation: 120768

Below is a fully working example. Note that this uses the pyqtSlot decorator to fix the problem. If that line is commented out, the example will no longer work, because the worker is moved to the thread after the slots are connected.

from PyQt5.QtCore import *
from PyQt5.QtWidgets import *

class Worker(QObject):
    started = pyqtSignal()
    finished = pyqtSignal()
    def __init__(self, message):
        super(Worker, self).__init__()
        self.message = message
    @pyqtSlot()
    def process(self):
        i = 0
        cicle = 10000
        j = 0
        while j < 5:
            i = i + 1
            if i % cicle == 0:
                j = float(i/cicle)
                print(self.message, j)
        print("Worker", int(QThread.currentThread().currentThreadId()))
        self.finished.emit()

app = QApplication(['test'])

worker1 = Worker("Worker 1:")
thread1 = QThread()
print("Main app:", int(QThread.currentThread().currentThreadId()))
thread1.started.connect(worker1.process)
worker1.finished.connect(thread1.quit)
worker1.finished.connect(worker1.deleteLater)
thread1.finished.connect(app.quit)
worker1.moveToThread(thread1)

thread1.start()

app.exec_()

Upvotes: 2

Gigino
Gigino

Reputation: 365

Ok,

I found that the problem was in the lambda function. Simply removing it solved the problem. The connection order does not affect the output. Here is the working example:

from PyQt5.QtCore import QObject, QThread, pyqtSignal


class Worker(QObject):
    started = pyqtSignal()
    finished = pyqtSignal()
    def __init__(self, message):
        super(Worker, self).__init__()
        self.message = message
    def process(self, message):
        i = 0
        cicle = 10000
        j = 0
        while j < 5:
            i = i + 1
            if i % cicle == 0:
                j = float(i/cicle)
                print(message, j)
        print("Worker", int(QThread.currentThread().currentThreadId()))
        self.finished.emit()

worker1 = Worker("Worker 1:")
thread1 = QThread()
thread1.started.connect(worker1.process(worker1.message))
worker1.finished.connect(thread1.quit)
worker1.finished.connect(worker1.deleteLater)
thread1.finished.connect(thread1.deleteLater)
worker1.moveToThread(thread1)
print("Main app:", int(QThread.currentThread().currentThreadId()))


thread1.start()

output:

Main App: 11624
Worker 1: 1.0
Worker 1: 2.0
Worker 1: 3.0
Worker 1: 4.0
Worker 1: 5.0
Worker 12552

There's absolutely no way for a new user to deduce this solution from the acepted answer here: PyQt: Connecting a signal to a slot to start a background operation .

Upvotes: -1

Related Questions