Dave
Dave

Reputation: 7603

Qt Thread Synchronization Design

I have a design problem which has been plaguing me for quite some time now. Essentially I have a function which takes long time to execute and a gui which needs to be responsive and up-to-date. When the user hits a start button the long function begins executing in a while loop and after each execution the gui needs to be updated.

I was thinking the best way of doing this was to have a QThread run in a while loop and if the user pressed a start button the long function would begin executing. similar to the following:

class Application : public QThread
{
    void run (void)
    {
        while (!mExiting)
        {
            if (StartPressed)
                LongFunction();

            // Need to update gui before
            // running long function again
        }
    }
}

I tried doing QMetaObject::Invoke with BlockingQueuedConnection however, when the gui application quits, the thread gets stuck and never exits. I also tried using a QMutex however, the gui would become locked waiting for the mutex which is locked and in use by the long function.

I was thinking, is there any way to cancel BlockingQueuedConnection when the application wants to quit or is there some other way of implementing this.

Upvotes: 0

Views: 691

Answers (1)

You're close, but you don't need to inherit from QThread. Instead:

  1. Put your computation into a slot in a QObject.

  2. Put the code that sets the exit flag into another slot (say Q_SLOT void finish();)

  3. Create an instance of the object. Create an instance of QThread. Call myObject->moveToThread(myThread).

  4. Start the thread.

  5. Connect gui signals to the slots in the computation object, similarly connect signals in the computation object that indicate that the data is ready.

  6. To end the processing and finish the thread, assuming that gui sends a stop() signal, set the following connections:

    1. connect(gui, SIGNAL(stop()), myObject, SLOT(finish()) - to stop your computation

    2. connect(gui, SIGNAL(stop()), myObject->thread(), SLOT(quit())) - to end the event loop in the thread

    3. connect(myObject->thread(), SIGNAL(finished()), myObject->thread(), SLOT(deleteLater()) - to delete the thread when the run() method returns

    You'll still need to delete myObject when you're done getting the results from it, or at least before your application exits.

Warning: It's an error to delete myObject if you're doing it from the gui thread and myObject->thread() is non-zero: you can't delete objects that have thread affinity different than current thread. A zero thread affinity means that no thread claims the object - in our case, when the object's thread is destructed. Then any thread can delete it.

For the same reason, you can't moveToThread an object that has a parent. The object that you move can have children, though, it just can't have a parent itself.

Upvotes: 1

Related Questions