c++qtqthreadqobjectqeventloop

Confusion regarding QThread, QObject, Thread Affinity and Event Loop


I was going through the links

  1. You are doing it wrong
  2. Using QThread in right way Part1
  3. Using QThread in right way Part2

I got confused by some statements. In the first link, it says that

all of the functions in QThread were written and intended to be called from the creating thread, not the thread that QThread starts.

while it suggests to use moveToThread to move an object to new thread, instead of subclassing QThread. My question is:

The default implementation of run method calls exec, which creates an event loop, and when an object's thread affinity is changed using moveToThread, all the slots will be executed in the new thread, not on the creating thread, which is contradictory with the aforementioned intended use. Am I missing something?

Second question:

In the third link it is said

event queue is belong to thread instead of event loop, and it’s shared by all the event loops running in this thread.

My question is how there can be more than one event loop in a single thread ? What I understand is, event-loop loop through the event-queue, until exit/terminate is called, and processes each event arrives on that queue. If this is true, one loop will never end (unless exit/terminate is called), how another can begin? Any sample code demonstrating it will be highly appreciated.


Solution

  • "which is contradictory with the aforementioned intended use. Am I missing something?"

    Yes, I think you're misunderstanding the concept of thread affinity (the thread on which an object is running).

    Let's take an example with minimal code: -

    QThread* pThread = new QThread; // QThread on the main thread
    MyObject* myObj = new MyObject; // MyObject on the main thread
    myObj->moveToThread(pThread);   // MyObject on the new thread, controlled by pThread
    pThread->start();               // pThread instance is still on the main thread
    

    Assuming this code has been created from an object whose thread affinity is the main thread, such as QMainWindow, the thread object pThread is running on the main thread; it's thread affinity is the main thread.

    In contrast, the QObject derived MyObject instance, myObj, has been moved to the new thread pThread. So, the thread affinity of myObj is now the new thread.

    The "functions written for QThread" are still called directly from the main thread, as that's where it's running.

    Think of QThread as a thread controller object, rather than the thread itself. This is one of the reasons why it is often discouraged to inherit from QThread, unless you want to change how QThread manages the underlying thread.

    how there can be more than one event loop in a single thread ?...

    I've not used this directly myself, but I'll try to explain this as I understand it. Perhaps someone else will be able to correct or confirm this. From the Qt Documentation for QEventLoop, it states: -

    At any time, you can create a QEventLoop object and call exec() on it to start a local event loop.

    The signature from QEventLoop exec is: -

    int QEventLoop::exec ( ProcessEventsFlags flags = AllEvents )

    So if you pass in a set of flags, only these events would be handled. Now, as calling exec() starts the processing of events until exit() is called, you can create a local event loop that lets your program wait until one or more specific events occur.

    A second event loop is a local event loop within the main event loop, but as each event loop can process the whole event queue, which is shared by all event loops in a thread, it can be used to override event handling from the main event loop.

    If you conceptualise an event loop as doing something like this (pseudo code): -

    QList<QEvent*> eventList;
    while(!stop)
    {
        // handle events in eventList
    }
    

    A 2nd event loop would then do this: -

    bool bStop = false;
    QList<QEvent*> eventList;
    while(!bStop)
    {
        // handle events in eventList
        ...
        ...
        // Inner event loop
        bool bStop = false;
        while(!bStop)
        {
            // handle events in eventList
        }
    }