Skip to content
Advertisement

Worker thread does not respond to slot calls from main thread

For my project based on Python and Qt I wanted to move expensive calculations and functions providing server/client functions into separate threads, to unfreeze my GUI. While leaving them running, I still want them to check periodically if there is new data from the main thread. For testing, I therefore implemented the following demo code:

JavaScript

My main aim was to let the “expensive” function run in the worker thread while counting up, but it should still check periodically if there is new data available (represented by a call to print_on_console_while_running). To avoid having the run-function blocking everything while it is executed, I also introduced a QTimer as non-blocking timer.

Still, regardless, whenever I press on the button with “Print to console!” while the worker is executing the run-function, I always get “Set print_to_console to true” printed after the run-function has finished, and not during execution, indicating that the run-function still blocks the execution of everything else.

What am I doing wrong here, and how can I send data from the main thread to the worker thread while still executing the run-function?

Advertisement

Answer

The problem is caused by the fact that the slot is in the receiver thread, so Qt automatically uses a QueuedConnection:

The slot is invoked when control returns to the event loop of the receiver’s thread. The slot is executed in the receiver’s thread.

Since the thread is occupied with the execution of run(), print_on_console_while_running will be called only as soon as run() returns.

A possible solution is to force a direct connection:

The slot is invoked immediately when the signal is emitted. The slot is executed in the signalling thread.

JavaScript

In this way, the slot is immediately called and the variable is instantly set.

Another, common approach (as long as the thread doesn’t need an actual event loop) is to directly subclass QThread and just override its run().

Since the QThread is the handler of the thread (no moveToThread is required), any connection made to any of its functions/slots will be in the same thread in which it was created (so, normally, the main thread), and only the run() will be executed in the separate thread, which means that implementing a print_on_console_while_running in that QThread subclass will always use a direct connection automatically.

Note that if you intend to start again the thread after its finished, you shouldn’t need to delete and recreate it again. Also note that that QTimer you’re creating is completely useless, not only because it doesn’t do anything when it times out, but mostly because time.sleep would prevent its processing. Finally, it’s usually better to avoid lambdas for thread connections, especially if the object is going to be destroyed.

User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement