Details
-
Bug
-
Resolution: Invalid
-
Not Evaluated
-
None
-
6.7.2
-
None
-
Brand new virtual environment, with python 3.12.2 and Pyside6 6.7.2.
Description
I seem to be unable to get QThread's `started` signal to behave properly.
When simply running the following:
import logging import time from PySide6 import QtCore logging.basicConfig(level=logging.INFO) class Controller(QtCore.QObject): def manage(self): worker = Worker() thread = QtCore.QThread() thread.started.connect(worker.do_work) worker.finished.connect(thread.quit) worker.moveToThread(thread) thread.start() self.worker_thread = thread class Worker(QtCore.QObject): finished = QtCore.Signal() @QtCore.Slot() def do_work(self): logging.info("Starting doing work") time.sleep(2) logging.info("Finished doing work") self.finished.emit() if __name__ == "__main__": controller = Controller() controller.manage() logging.info("Returned from `controller.manage()`") controller.worker_thread.wait(2000)
the `do_work` method is never run. This is the output:
INFO:root:Returned from `controller.manage()` Process finished with exit code 0
Also note that not inheriting QObject for Controller leads to this exit code:
Process finished with exit code -1073740791 (0xC0000409)
which I believe is linked to killing a QThread while it is running.
The only workaround that I have found to run the method is to connect the `worker.do_work` slot to a dummy signal. By connecting `controller.dummy_signal` to `worker.do_work`, the slot is called correctly in the worker thread, even though the dummy signal is never emitted. I've tested it with a barebones `QtWidgets.QApplication` and the GUI is responsive while the worker does work which indicates it is indeed running in another thread.
Another requirement is that the `thread.started.connect(worker.do_work)` connection does not have a specified connection type. Trying any value of the enum leads to the worker method not running (even using `AutoConnection` which is the default).
However, providing a connection type for the dummy signal connection is also required and using any value from the enum leads to the application working (if previous conditions are fullfilled).
Here is the working example:
import logging import time from PySide6 import QtCore logging.basicConfig(level=logging.INFO) class Controller(QtCore.QObject): dummy_signal = QtCore.Signal() def manage(self): worker = Worker() thread = QtCore.QThread() thread.started.connect(worker.do_work) worker.finished.connect(thread.quit) worker.moveToThread(thread) thread.start() self.dummy_signal.connect(worker.do_work, QtCore.Qt.DirectConnection) self.worker_thread = thread class Worker(QtCore.QObject): finished = QtCore.Signal() @QtCore.Slot() def do_work(self): logging.info("Starting doing work") time.sleep(2) logging.info("Finished doing work") self.finished.emit() if __name__ == "__main__": controller = Controller() controller.manage() logging.info("Returned from `controller.manage()`") controller.worker_thread.wait(2000)
Which outputs:
INFO:root:Starting doing work INFO:root:Returned from `controller.manage()` INFO:root:Finished doing work Process finished with exit code 0
I'm still relatively knew to Pyside so I'm more than happy to be corrected if there is something wrong with my approach but this does appear to be unexpected behaviour.
In summary:
Connecting QThread's `started` signal has no effect unless the target of the signal is also connected to another dummy signal.