Event loops and signal-slot processing when using multithreading in Qt Event loops and signal-slot processing when using multithreading in Qt multithreading multithreading

Event loops and signal-slot processing when using multithreading in Qt


All results you got are perfectly correct. I'll try to explain how this works.

An event loop is an internal loop in Qt code that processes system and user events. Event loop of main thread is started when you call a.exec(). Event loop of another thread is started by default implementation of QThread::run.

When Qt decides it's time to process an event, it executes its event handler. While event handler is working, Qt has no chance to process any other event (unless given directly by QApplication::processEvents() or some other methods). Once the event handler is finished, control flow returns to the event loop and Qt may execute another handler to process another event.

Signals and slots are not the same as events and event handlers in Qt terminology. But slots are handled by event loops somewhat similarily. If you have control flow in your code(such as in main function) you can execute any slot immediately just as any other C++ function. But when Qt does that it can only do that from an event loop. It should be noted that signals are always sent immediately, while slot execution may be delayed.

Now let's see what happens in each case.

Case 1

WorkerManager::process is executed directly at the program start. New thread is started and Worker::process is executed immediately in the new thread. WorkerManager::process continues execution until Worker is done, freezing all other actions (including slot processing) in main thread. After WorkerManager::process is finished, control flow goes to QApplication::exec. Qt establishes connection to the other thread, receives messages about slot invokation and invokes all of them consequently.

Case 2

Qt by default executes slots of an object in the thread this object belongs to. Main thread will not execute slots of WorkerManager because it belongs to another thread. However this thread is never started. Its event loop is never finished. Invokations of slot1 and slot2 are left forever in Qt's queue waiting for you to start the thread. Sad story.

Case 3

In this case WorkerManager::process is executed in main thread because you invoke it directly from main thread. Meanwhile, WorkerManager's thread is started. Its event loop is launched and waiting for events. WorkerManager::process starts Worker's thread and executes Worker::exec in it. Worker starts sending signals to WorkerManager. WorkerManager's thread almost immediately starts to execute appropriate slots. At this point it seems awkward that WorkerManager::slot2 and WorkerManager::process are executed simultaneously. But it's perfectly fine, at least if WorkerManager is thread-safe. Shortly after Worker is done, WorkerManager::process is finished and a.exec() is executed but has not much to process.

Case 4

Main function just launches WorkerManager's thread and immediately goes to a.exec(), resulting in end as first line in the output. a.exec() processes something and ensures program execution but doesn't execute WorkerManager's slots because it belongs to another thread. WorkerManager::process is executed in WorkerManager's thread from its event loop. Worker's thread is started and Worker::process starts sending signals from Worker's thread to WorkerManager's thread. Unfortunately the latter is busy executing WorkerManager::process. When Worker is done, WorkerManager::process also finishes and WorkerManager's thread immediately executes all queued slots.

The largest problem in your code is usleep and infinite loops. You should almost never use those when working with Qt. I understand that a sleep in Worker::process is just a placeholder for some real calculation. But you should remove sleep and infinite loop from WorkerManager. Use WorkerManager::slot1 to detect Worker's termination. If you develop a GUI application there would be no need to move WorkerManager to another thread. All its methods (without sleep) will be executed fast and will not freeze the GUI.