[SOLVED] Thread event loop not working when the main application is blocked.



  • Hi,

    I have a quite simple problem that is driving me crazy.

    I have some operations that are performed on a thread. I have an object that's doing the heavy job, and I'm moving it to a thread, as suggested in http://labs.qt.nokia.com/2010/06/17/youre-doing-it-wrong/
    The object is created the following way

    @MainDialog::MainDialog(QWidget parent, Qt::WindowFlags f)
    : QDialog(parent, f)
    {
    /
    ... */

    myThread = new QThread(this);

    myObject = new MyObject;
    myObject->moveToThread(myThread);

    connect( myThread, SIGNAL( started() ),
    myObject, SLOT( start() ) );
    connect( myObject, SIGNAL( finished() ),
    myThread, SLOT( quit() ) );
    }@

    Ideally when I start myThread the start() slot should be called on myObject and when myObject emits the finished() signal my thread should quit.

    The implementation of MyObject is as simple as this

    @void MyObject::start()
    {
    QTimer::singleShot( 0, this, SLOT(doOperation()) );
    }

    void MyObject::doOperation()
    {
    if( stopped() )
    {
    emit finished();
    return;
    }

    /* ... */

    QTimer::singleShot(1000, this, SLOT(doOperation()));
    }

    void MyObject::stop()
    {
    QMutexLocker ml(&_mutex);

    _stopped = true;
    }

    bool MyObject::stopped() const
    {
    QMutexLocker ml(&_mutex);

    return _stopped;
    }
    @

    Essentially an operation is performed periodically till the operation is not stopped through the stop() method.
    On the main application I start the thread

    @void MainDialog::onStartClicked()
    {
    myThread->start();
    }@

    and myObject starts working as expected.
    The problem happens when I stop the object flow calling the stop function

    @void MainDialog::onStopClicked()
    {
    myObject->stop();

    myThread->wait();

    /* ... */
    }
    @

    the wait() on myThread freezes my application and the quit() slot on myThread is never called.
    I really do not understand why, since the thread has its own event loop.

    I'm using Qt 4.7.3 on Windows.

    Thanks in advance for your help.



  • Your thread myThread is not in the context of another thread but rather in the context on the main thread where it was created. I guess thats why your app is freezing.

    Why do you wait for the thread instance anyways?

    Maybe "this":http://developer.qt.nokia.com/forums/viewthread/6541/P15 is helpfull for your problem with your thread not executing the quit slot.



  • KA510,

    [quote author="KA51O" date="1328625359"]Your thread myThread is not in the context of another thread but rather in the context on the main thread where it was created. I guess thats why your app is freezing.[/quote]

    you're right, the wait on the thread blocks the main application, but the event loop of the thread should still be executing, so the finished() signal emitted by myObject should properly trigger the call of the quit() function on myThread, that's what I do not understand.

    [quote author="KA51O" date="1328625359"]
    Why do you wait for the thread instance anyways?[/quote]
    I'm waiting for the thread to finish because I need to do other stuff only when I'm sure the thread has stopped, I did not write that in the example code for simplicity reasons.

    [quote author="KA51O" date="1328625359"]
    Maybe "this":http://developer.qt.nokia.com/forums/viewthread/6541/P15 is helpfull for your problem with your thread not executing the quit slot.[/quote]

    My case is slightly different, The finished signal is emitted by myObject, and that should trigger the stop of the thread.



  • If you emit a signal from myObject to MainDialog it is posted to the event queue of the thread MainDialog lives in, the main thread. The main thread is blocked, because it is waiting for myThread to finish. myThread on the other hand is never finished, because the event loop in myThread keeps running unless exit() is called - what you don't do.
    @
    void MyObject::doOperation()
    {
    if( stopped() )
    {
    emit finished();

    thread()->exit(); // stop event loop and finish myThread, wait() returns
    // and main thread processes the signal event

    return;
    }

    /* ... */

    QTimer::singleShot(1000, this, SLOT(doOperation()));
    }
    @



  • Did you call exec in myThread's run function?



  • The default implementation of run() calls exec().



  • Thanks Lukas,
    your trick worked!

    As I could understand the thread object belongs to the main application, so the events sent to that object are handled by the main event loop. That explains why the finished() signal was never handled.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.