1

I'm trying to let a button spin up a new thread that does nothing but sleep for 30 seconds. However, the main thread is blocked if the slot is a lambda function. Does anyone know why this is the case and not behaving what I was expecting it to be? Here's my code:

    # ...
    def setup(self):
        # ...
        self.pushButton_TestConnection.clicked.connect(self.process)

    def process(self):
        self.worker_thread = QtCore.QThread()
        self.worker = Worker()
        self.worker.moveToThread(self.worker_thread)
        self.worker_thread.started.connect(lambda: self.worker.sleep(30))

        self.worker_thread.start()

class Worker(QtCore.QObject):
    def sleep(self, secs):
        time.sleep(secs)

It works fine with the following

     self.worker_thread.started.connect(self.worker.sleep)

        self.worker_thread.start()

class Worker(QtCore.QObject):
    def sleep(self):
        time.sleep(30)

Thanks

Kar
  • 6,063
  • 7
  • 53
  • 82

1 Answers1

3

In Qt the thread in which code is executed is determined by the thread affinity of the object receiving a signal. If you call a objects method directly from a different thread, it will be executed in the calling thread, no matter the thread affinity of the called object.

Lambdas and other python callables do not have a thread affinity (they're not QObjects after all, it's just a nice feature of PyQt allowing you to connect a signal to any python callable), so they will always be executed in the main (GUI) thread.
So in this case the lambda is executed in the GUI thread, so the worker.sleep call will also be executed there and will block it until the call returns.

To make this work, you need to connect the started signal directly to a slot of the Worker object, or communicate with the Worker using a signal you emit from the lambda.

mata
  • 67,110
  • 10
  • 163
  • 162