Results 1 to 15 of 15

Thread: Workload in a QThread blocks main application's event loop ?

  1. #1
    Join Date
    Feb 2006
    Posts
    9
    Thanks
    2
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Unhappy Workload in a QThread blocks main application's event loop ?

    Hello, I'm trying to implement a simple gui with a worker thread using Qt 4.1.1

    My gui is managed in the QApplication's event loop. The worker thread also has its event loop.

    The worker thread starts some work when the GUI emits a defined signal (Qt::QueuedConnection because signal->slot are in different threads).

    (of course,) the worker thread interrupts its event loop to do its job. The worker thread emits signals back to the gui thread to report progress, and that on a regular basis (to display a nice QProgressBar). The worker thread doesn't return to it's event loop until the job is finished.

    The problem: my GUI thread does not process any event (coming from the worker thread) until the worker thread finishes its job and returns to its event loop.

    Same problem in the other direction. When the user quits the programm, the GUI emits a signal ("request finish") to the worker thread so that it finishes, the GUI then wait() for the worker thread's termination. But the worker thread never handles the "request finish" signal until the GUI thread returns to its event loop. The code below illustrates that and locks both threads.

    Qt Code:
    1. // GUI code, this is a slot; auto connected by moc.
    2. void on_exitButon_clicked(void) {
    3. QTimer::singleShot(0, workerThread, SLOT(stopThread(void)));
    4. workerThread->wait();
    5. close();
    6. }
    To copy to clipboard, switch view to plain text mode 

    This is really strange, I already worked with threads, but never in Qt. It seems here that when a thread blocks the other are not scheduled.

    Thanks for your time!

  2. #2
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    5,372
    Thanks
    28
    Thanked 975 Times in 912 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Workload in a QThread blocks main application's event loop ?

    Quote Originally Posted by 0xBulbizarre
    Qt Code:
    1. // GUI code, this is a slot; auto connected by moc.
    2. void on_exitButon_clicked(void) {
    3. QTimer::singleShot(0, workerThread, SLOT(stopThread(void)));
    4. workerThread->wait();
    5. close();
    6. }
    To copy to clipboard, switch view to plain text mode 
    This slot won't be triggered, because you block the event loop with "workerThread->wait()" and timer event can't be processed. Try sending an event to that thread.

  3. The following user says thank you to jacek for this useful post:

    0xBulbizarre (19th March 2006)

  4. #3
    Join Date
    Feb 2006
    Posts
    9
    Thanks
    2
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Workload in a QThread blocks main application's event loop ?

    Quote Originally Posted by jacek
    This slot won't be triggered, because you block the event loop with "workerThread->wait()" and timer event can't be processed. Try sending an event to that thread.
    Ok, thank you for that one.

    In fact, I wanted to avoid a connect() to do only 1 emit, that's why I used the one shot timer. Is there a way (1 liner) to trigger a slot of another thread?

    You can also certainly explain me that one. Similar problem as describved above, but in the worker thread. The threadProgressing() signal (Qt::QueuedConnection) is only received by the GUI thread when the worker thread returns to the event loop. Is emit effectively only happening in the event loop?

    Qt Code:
    1. // code executed by workerThread
    2. // this is the slot called from the GUI thread (see post above)
    3. void OtherThread::stopThread(void)
    4. {
    5. starting = false;
    6. for (int i = 100; i > 0; i--) {
    7. msleep(100);
    8. emit threadProgressing(i);
    9. // uncommenting following line solves the problem, what is the best practice here ?
    10. //QCoreApplication::processEvents();
    11. }
    12. emit threadStopped();
    13. quit();
    14. }
    To copy to clipboard, switch view to plain text mode 

    Thank you

  5. #4
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    5,372
    Thanks
    28
    Thanked 975 Times in 912 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Workload in a QThread blocks main application's event loop ?

    Quote Originally Posted by 0xBulbizarre
    Is there a way (1 liner) to trigger a slot of another thread?
    You could try to send QMetaCall event, but it probably won't fit in one line. Maybe you could add a boolean flag and some method that sets it when thread should stop itself?

    Quote Originally Posted by 0xBulbizarre
    The threadProgressing() signal (Qt::QueuedConnection) is only received by the GUI thread when the worker thread returns to the event loop. Is emit effectively only happening in the event loop?
    The docs say:
    With queued connections, the slot is invoked when control returns to the event loop of the thread to which the object belongs. The slot is executed in the thread where the receiver object lives.
    Unless something has changed in Qt 4.1.1, sender doesn't even need to live in a thread with a running event loop (see the Mandelbrot example --- there's no event loop running in RenderThread).

  6. #5
    Join Date
    Feb 2006
    Posts
    9
    Thanks
    2
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Workload in a QThread blocks main application's event loop ?

    Quote Originally Posted by 0xBulbizarre
    The threadProgressing() signal (Qt::QueuedConnection) is only received by the GUI thread when the worker thread returns to the event loop. Is emit effectively only happening in the event loop?
    Quote Originally Posted by jacek
    The docs say:
    With queued connections, the slot is invoked when control returns to the event loop of the thread to which the object belongs. The slot is executed in the thread where the receiver object lives.
    Unless something has changed in Qt 4.1.1, sender doesn't even need to live in a thread with a running event loop (see the Mandelbrot example --- there's no event loop running in RenderThread).
    My problem here is that (it seems) the signal is not sent until control returns to the event loop of the _sender_, although the receiver is in its event loop during all that time.

  7. #6
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    5,372
    Thanks
    28
    Thanked 975 Times in 912 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Workload in a QThread blocks main application's event loop ?

    Quote Originally Posted by 0xBulbizarre
    My problem here is that (it seems) the signal is not sent until control returns to the event loop of the _sender_, although the receiver is in its event loop during all that time.
    Do you actually start that second thread?

  8. #7
    Join Date
    Feb 2006
    Posts
    9
    Thanks
    2
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Workload in a QThread blocks main application's event loop ?

    Quote Originally Posted by jacek
    Do you actually start that second thread?
    Yes (of course), the second's thread run() method is :
    Qt Code:
    1. void run()
    2. {
    3. exec();
    4. }
    To copy to clipboard, switch view to plain text mode 

    Do you want some test code to experiment with, do you need more infos ?

  9. #8
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    5,372
    Thanks
    28
    Thanked 975 Times in 912 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Workload in a QThread blocks main application's event loop ?

    Quote Originally Posted by 0xBulbizarre
    Yes (of course), the second's thread run() method is :
    That's the run() method, but how do you start that thread?

  10. #9
    Join Date
    Feb 2006
    Posts
    9
    Thanks
    2
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Workload in a QThread blocks main application's event loop ?

    Quote Originally Posted by jacek
    That's the run() method, but how do you start that thread?
    I start it from gui thread with
    Qt Code:
    1. otherThread = new OtherThread(this);
    2. otherThread->start();
    To copy to clipboard, switch view to plain text mode 

    OtherThread's declaration:
    Qt Code:
    1. class OtherThread : public QThread
    To copy to clipboard, switch view to plain text mode 

  11. #10
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    5,372
    Thanks
    28
    Thanked 975 Times in 912 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Workload in a QThread blocks main application's event loop ?

    Quote Originally Posted by 0xBulbizarre
    otherThread = new OtherThread(this);
    otherThread->start();
    Looks OK, did you try with 0 instead of "this"?

  12. #11
    Join Date
    Feb 2006
    Posts
    9
    Thanks
    2
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Workload in a QThread blocks main application's event loop ?

    Quote Originally Posted by jacek
    Looks OK, did you try with 0 instead of "this"?
    yes, but nothing changes (apparently).


    I think I found something... The slot executed by the singleShot timer shall be executed by the worker thread, but is in fact executed by the GUI thread. So, I deduce that the connection created by the singleShot timer is a DirectConnection instead of a QueuedConnection. That would explain why the slot is executed by the emitting thread.

    Here is how I create the worker thread, and how I create the singleShot() timer
    Qt Code:
    1. // code from the GUI thread
    2. otherThread = new OtherThread(this);
    3. otherThread->start();
    4. QTimer::singleShot(0, otherThread, SLOT(startThread(void)));
    5. cout << "In GUI Thread, Thread=" << currentThread() << " ThreadID=" << currentThreadId() << endl;
    6. QCoreApplication::processEvents(); // process the timer event
    To copy to clipboard, switch view to plain text mode 

    here is my startThread() function (from the worker thread)
    Qt Code:
    1. void OtherThread::startThread(void) {
    2. cout << "In startThread() Thread=" << currentThread() << " ThreadID=" << currentThreadId() << endl;
    3. // do some job...
    4. }
    To copy to clipboard, switch view to plain text mode 

    outputs where we can see that the GUI thread executes the slot instead of the worker thread:
    In GUI Thread, Thread=0x804f198 ThreadID=3078543040
    In startThread() Thread=0x804f198 ThreadID=3078543040

    Where is my mistake ? should QTimer::singleShot()'s receiver be something else that my otherThread ?

  13. #12
    Join Date
    Feb 2006
    Posts
    9
    Thanks
    2
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Workload in a QThread blocks main application's event loop ?

    I saw in the docs that:
    By default, QObject::connect() establishes a direct connection if the sender and the receiver live in the same thread, and a queued connection if they live in different threads.
    If we look at my code above (reproduced below)... we can see that both the sender and the receiver live in the same thread. The sender is the singleShot timer, the receiver is a thread object, also living in the GUI thread.
    Qt Code:
    1. otherThread = new OtherThread(this);
    2. otherThread->start();
    3. QTimer::singleShot(0, otherThread, SLOT(startThread(void)));
    To copy to clipboard, switch view to plain text mode 

    is it correct ? how to solve that problem ?

  14. #13
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    5,372
    Thanks
    28
    Thanked 975 Times in 912 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Workload in a QThread blocks main application's event loop ?

    QThread object lives in the thread that created it. You could split that class into two --- the thread itself and an object that lives within that thread.

  15. The following user says thank you to jacek for this useful post:

    0xBulbizarre (20th March 2006)

  16. #14
    Join Date
    Feb 2006
    Posts
    9
    Thanks
    2
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Workload in a QThread blocks main application's event loop ?

    Ok, I now understand why a QThread should'nt do any business logic directly. I'll try that tonight!

    thanks for what I learned in this (forum) Thread !

  17. #15
    Join Date
    Apr 2006
    Posts
    7
    Thanked 4 Times in 1 Post
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Workload in a QThread blocks main application's event loop ?

    Try this

    otherThread = new OtherThread(this);
    otherThread->moveToThread(otherThread);
    otherThread->start();

    that should work ... Regards Madrich

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.