Results 1 to 17 of 17

Thread: QThread, moveToThread question

  1. #1
    Join Date
    Feb 2013
    Posts
    19
    Thanks
    4
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default QThread, moveToThread question

    Hi together,

    I have some problems with understanding the behaviour of my following code...
    I tryed to udnerstand the Threading in Qt, so i found a nice youtube vid which i would like to share with you - its from Dario Freddi http://www.youtube.com/watch?v=MMFhc2jXzgw


    I Wrote a simple application to try movetothread methode, just 2 Workers and a QWidget class with a button. on button clicked worker 1 starts -> in its cTor it creates worker2 and waits of the finish signal from worker2. But some code say more than words so.
    i can post the whole simple project, but i dont know if its ok, so i just post the some few lines of code.

    QWidget:
    Qt Code:
    1. void Widget::on_btTest_clicked()
    2. {
    3. QTime time;
    4. time.start();
    5. worker1 *worker = new worker1;
    6. worker->doWork1();
    7. qDebug() << time.elapsed() << "mseconds" << "current time:" << time.currentTime().toString("hh:mm:ss:z")<< "worker1 result" << worker->getRes();
    8. }
    To copy to clipboard, switch view to plain text mode 

    Worker1:
    Qt Code:
    1. worker1::worker1(QObject *parent) :
    2. QObject(parent),
    3. m_classThread(new QThread),
    4. m_resultString("Hallo")
    5. {
    6. moveToThread(m_classThread);
    7. m_worker2 = new Worker2;
    8. //breaks the own event loop if worker 2 is finished
    9. connect(m_worker2, SIGNAL(workDone()), &wait, SLOT(quit()));
    10. connect(this, SIGNAL(startNow()), m_worker2, SLOT(doWork2()));
    11. m_classThread->start();
    12. }
    13.  
    14. void worker1::doWork1()
    15. {
    16. //starts worker2 und wartet auf sein finished
    17. qDebug() << Q_FUNC_INFO;
    18. emit startNow();
    19. wait.exec();
    20. }
    21.  
    22. QString worker1::getRes()
    23. {
    24. return m_resultString;
    25. }
    To copy to clipboard, switch view to plain text mode 

    Worker2:
    Qt Code:
    1. Worker2::Worker2(QObject *parent) :
    2. QObject(parent),
    3. m_classThread(new QThread),
    4. m_resultString("123")
    5. {
    6. moveToThread(m_classThread);
    7. tima.setInterval(5000);
    8. tima.start();
    9. m_classThread->start();
    10. }
    11.  
    12. void Worker2::doWork2()
    13. {
    14. qDebug() << Q_FUNC_INFO;
    15. // create a event loop for the timer to be finished
    16. QEventLoop wait;
    17. connect(&tima, SIGNAL(timeout()), &wait, SLOT(quit()));
    18. wait.exec();
    19. emit workDone();
    20.  
    21. }
    To copy to clipboard, switch view to plain text mode 



    Results in the Debug frame:
    Qt Code:
    1. void worker1::doWork1()
    2. void Worker2::doWork2()
    3. void worker1::doWork1()
    4. void Worker2::doWork2()
    5. 5003 mseconds current time: "15:35:22:36" WIDGET: worker one "Hallo"
    6. 7204 mseconds current time: "15:35:22:36" WIDGET: worker one "Hallo"
    To copy to clipboard, switch view to plain text mode 


    So here is my missunderstood/question -> if i click the button twice with a simple delay of 2 seconds, why get i the results at the same time? Why i dont get the debug msg of the first click on the button from(worker.getRes() (in the widget class) not 2 seconds earlier than the msg of the 2nd click?

    If I may suggest, then I would argue that the problem is that the queue for the widget/main thread queue is accessed when the 2nd click -> workers are finished? So the first debug msg got queued at the mainthread and fired when the last work is done? But i dont get it exactly whats the problem here.

    It would be very nice if s.o can explain me the above behaviour. An it would be really nice , to see how to solve this "problem". thanks!
    (if u want me to post the project as attachement - just tell me....)

    TIA Anenja!

  2. #2
    Join Date
    Jan 2006
    Location
    Germany
    Posts
    4,380
    Thanks
    19
    Thanked 1,005 Times in 913 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows Symbian S60
    Wiki edits
    5

    Default Re: QThread, moveToThread question

    Hi, in worker1::doWork1(): what is "wait"?

    Further, when you use moveToThread, you have to call slots by using signals. If you call them via "->" the function is executed in the same thread as the caller. (In the video he is connecting the QThread::started() with a moved object slot.). Also if you move Worker2 to a Thread, there is - I think, since I am also no thread expert - no need for an event loop inside.

  3. #3
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: QThread, moveToThread question

    Quote Originally Posted by Lykurg View Post
    Also if you move Worker2 to a Thread, there is - I think, since I am also no thread expert - no need for an event loop inside.
    The base implementation of QThread::run() already runs an event loop (see QThread::exec(), QThread::quit()), but a nested event loop is not wrong either. Depends on whether you want to keep the thread itself running.

    I agree that worker1->doWork1() looks wrong since it totally bypasses the first thread. One would expect that the widget's code connects to some sort of result signal and then starts the first thread.

    Cheers,
    _

  4. #4
    Join Date
    Feb 2013
    Posts
    19
    Thanks
    4
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QThread, moveToThread question

    Hi, in worker1::doWork1(): what is "wait"?
    Thanks for your help!
    wait is just an eventLoop.
    I Dont subclass qthread so i need a own eventloop if i want to wait for s.th at this point within this thread.

    I agree that worker1->doWork1() looks wrong since it totally bypasses the first thread
    Thanks for your help!
    Ok i understand this. Still if i connect doWork1() to the thread started() signal, in its cTor it dont fix the behaviour.


    What i think what happens:
    I create a worker object on bt_clicked() in the MainThread, then in workers cTor the object is moved to it´s own thread, then in the cTor of worker1 I create worker2 (in the mainthread - cause the thread of worker 1 hasn´t started yet, then in workers2 cTor the object is moved to its own thread. So, worker1 life in its thread an worker 2 does. worker 1 waits in it´s own QEventloop for worker2 to be finished.
    the debug msg of the threadID´s confirm the things i wrote above.

    i fix the code so only signal/slots will be used...
    Qt Code:
    1. //breaks the own event loop if worker 2 is finished
    2. connect(m_worker2, SIGNAL(workDone()), &wait, SLOT(quit()));
    3. // signal startNow is emitted in doWork1()
    4. connect(this, SIGNAL(startNow()), m_worker2, SLOT(doWork2()));
    5. connect(m_classThread, SIGNAL(started()), this, SLOT(doWork1()));
    6. m_classThread->start();
    7. wait.exec();
    To copy to clipboard, switch view to plain text mode 

    QWidget:
    Qt Code:
    1. ....
    2. worker1 *worker = new worker1;
    3. qDebug() << "this debug msg will executed if worker1 is finished ";
    4. ....
    To copy to clipboard, switch view to plain text mode 


    I really try to solve this and understand it - but i dont know if i am right here.
    I click the button and the eventqueue of worker1 blocks the go on in the next line of code (in slot bt_clicked()) - thats ok i can understand this, but if i click this button again why are the debug mgs fired at the same time together?
    if I add an other button on the widget i can click this bt while the threads are running (on click just show a debug msg) and it is fired instantly.

    I hope u can follow/understand me, my english is not really good -.-

    debug console:
    Qt Code:
    1. Worker1 created()
    2. "another widget bt bt_clickedNew tho show just a debug msg"
    3. Worker1 created()
    4. "another widget bt bt_clickedNew tho show just a debug msg"
    5. 5002 mseconds current time: "12:40:14:355" WIDGET: worker one QThread(0x851cb90) "Hallo"
    6. 6987 mseconds current time: "12:40:14:355" WIDGET: worker one QThread(0x840ce58) "Hallo"
    To copy to clipboard, switch view to plain text mode 


    Thanks for your help!
    Last edited by Anenja; 24th February 2013 at 11:47.

  5. #5
    Join Date
    Sep 2011
    Posts
    1,241
    Thanks
    3
    Thanked 127 Times in 126 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: QThread, moveToThread question

    why don't you use your debugger and some breakpoints to see what is happening?
    If you have a problem, CUT and PASTE your code. Do not retype or simplify it. Give a COMPLETE and COMPILABLE example of your problem. Otherwise we are all guessing the problem from a fabrication where relevant details are often missing.

  6. #6
    Join Date
    Feb 2013
    Posts
    19
    Thanks
    4
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QThread, moveToThread question

    amleto

    Re: QThread, moveToThread question
    why don't you use your debugger and some breakpoints to see what is happening?
    Thanks for your help.
    Hi, i tryed to debug it, but i dont get anything useful information out of it

    i really dont get the point where i did the mistake or the missunderstand happens. perhaps s.o can have a quick look at it -> i put the project as attachment.

    Thanks again, really nice to get all ur help.!
    Attached Files Attached Files

  7. #7
    Join Date
    Sep 2011
    Posts
    1,241
    Thanks
    3
    Thanked 127 Times in 126 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: QThread, moveToThread question

    If you dont get anything useful then add more. Learning how to debug is not optional for programmers.

    What you have is frankly a mess of threads and timers in object that aren't moving in the same threads as their owners etc. Why don't you time how long worker 1 takes. It should be about 5s, right? Sometimes for me it is 5s, sometimes 7s. You should look into that if you are doing this just as problem solving. If you want to write some code for learning purpose, I suggest you throw away what you've done and write it properly.
    If you have a problem, CUT and PASTE your code. Do not retype or simplify it. Give a COMPLETE and COMPILABLE example of your problem. Otherwise we are all guessing the problem from a fabrication where relevant details are often missing.

  8. #8
    Join Date
    Feb 2013
    Posts
    19
    Thanks
    4
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QThread, moveToThread question

    Quote Originally Posted by amleto View Post
    If you dont get anything useful then add more. Learning how to debug is not optional for programmers.

    What you have is frankly a mess of threads and timers in object that aren't moving in the same threads as their owners etc. Why don't you time how long worker 1 takes. It should be about 5s, right? Sometimes for me it is 5s, sometimes 7s. You should look into that if you are doing this just as problem solving. If you want to write some code for learning purpose, I suggest you throw away what you've done and write it properly.
    Thank you amleto.

    i checked the timer variable and its thread and u are right the timer is in the mainthread home created and the object itself is moved to another thread.
    i will debug it harder and try to rewrite it properly.

    a question i got:
    Worker *work = new Worker; //created in the current thread and ALL membervars are also created in this thread
    If u now use moveToThread(t1) -> are the member vars still in the "old" thread, so is this a problem ?

    TIA

  9. #9
    Join Date
    Sep 2011
    Posts
    1,241
    Thanks
    3
    Thanked 127 Times in 126 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: QThread, moveToThread question

    all member vars of the instance that have not had their parent set to the instance will not move when the instance is moved.
    If you have a problem, CUT and PASTE your code. Do not retype or simplify it. Give a COMPLETE and COMPILABLE example of your problem. Otherwise we are all guessing the problem from a fabrication where relevant details are often missing.

  10. #10
    Join Date
    Feb 2013
    Posts
    19
    Thanks
    4
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QThread, moveToThread question

    amleto

    Re: QThread, moveToThread question
    all member vars of the instance that have not had their parent set to the instance will not move when the instance is moved.
    ok thanks i got this.

    I also got my logical Problem in the above code. Debugger helps me to get it

    I Created an event loop in the cTor of Worker1 -> eventloop is created in the mainthread and is not moved (i think u cant move this loop cause it makes no sense or? - if i create a loop in a slot and moved the object in the ctor all is fine, the loop is created in the object thread <-parent is the object ....) The loop in the cTor stops the application to move on in the code (sry for this explanation but i really dont know how to explain this). what i mean is:
    Qt Code:
    1. line 9: ....
    2. line 10: Worker1 * worker = new Worker1; // at this point the cTor loop stops the further going to line 11 until the loop is finished
    3. line 11: qDebug() << "....."
    To copy to clipboard, switch view to plain text mode 

    So if i am right, the eventloop which "lives" in the mainthread created in the cTor (line 10) is the reason why the qDebug msg are fired at the same time - if i click the button twice.
    This i cause the eventloop of worker1 is started in the cTor, after 5 seconds worker2 quits this loop, but the new click on the button creates a new eventloop which again blocks the go on to line 11 (-> there can only be one eventloop in a thread right?) so after the new worker1 created by clicking the button again "reopens" the event queue (by creating a new in the mainthread) - if worker2 is now finished this eventloop is leaved and the qDebug msgs appear both at the same time.

    It would be really nice if s.o can tell me if iam right - this is the result i got from debugging and this behaviour makes sense to me.

    Thanks again and have a nice sunday

  11. #11
    Join Date
    Sep 2011
    Posts
    1,241
    Thanks
    3
    Thanked 127 Times in 126 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: QThread, moveToThread question

    there can be many event loops in a thread, and this is in fact your problem. If this didn't happen, you wouldn't be able to press the button for a second time since your worker1 is blocking the main thread. The only reason the gui remains responsive is because you start a second event loop in the main thread. When you get 'recursive' event loops, Qt does some managing of which signals and slots to process based on recursion level (I think) - this will be why your signal/slot from the first button press are delayed until after the second button press's signals have been processed.
    If you have a problem, CUT and PASTE your code. Do not retype or simplify it. Give a COMPLETE and COMPILABLE example of your problem. Otherwise we are all guessing the problem from a fabrication where relevant details are often missing.

  12. #12
    Join Date
    Feb 2013
    Posts
    19
    Thanks
    4
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QThread, moveToThread question

    amleto

    Re: QThread, moveToThread question
    there can be many event loops in a thread, and this is in fact your problem. If this didn't happen, you wouldn't be able to press the button for a second time since your worker1 is blocking the main thread. The only reason the gui remains responsive is because you start a second event loop in the main thread. When you get 'recursive' event loops, Qt does some managing of which signals and slots to process based on recursion level (I think) - this will be why your signal/slot from the first button press are delayed until after the second button press's signals have been processed.
    hi, thanks again for ur reply.

    Ok i understand this ...

    My Idea was to achieve s.th like this -
    Qt Code:
    1. //create a worker and wait for its result
    2. Line: 10: Worker1 *worker = new Worker1("params for some work");
    3. //save the result of worker in the example String
    4. Line 11: QString exampleString = worker->getRes();
    5. // create a new Worker with the result of the first worker and start a new job with this result
    6. Line 12: Worker1 *anotherTask = new Worker1(exampleString + "more nasty work");
    7. line 13: qDebug() << "worker1 result" << worker->getRes() << " 2nd Worker res (based on the first worker res)" << anotherTask->getRes();
    To copy to clipboard, switch view to plain text mode 

    If this would work, i simply can move existing class to stop freezinig GUI and dont have to change the code at all, all i had to to is write a wrapper for the old class and replace the old class name with the new one in my code and i dont need do modify exissting codebrackets... But this was just an idea of using threads which probably doesnt work huh?
    If i create worker1, and use the worker like in the code above i want to wait for its result - but i see there is probably no way to use this like the code above - i have to do this via signal/slots - right?
    s.th like this:
    Qt Code:
    1. //create a worker and wait for its result
    2. ..QThread t1;
    3. Line 10: Worker1 *worker = new Worker1("params for some work");
    4. worker->moveToThread(&t1)
    5. // connect the worker with its finished signal, an start new worker with the result
    6. connect(worker, SIGNAL(started), worker, SLOT(startWork());
    7. Line 11: connect(worker, SIGNAL(finished()), this, SLOT(worker1FinishedSlotStartWorker2WiththeNewResult());
    8. worker->start();
    9. ....
    To copy to clipboard, switch view to plain text mode 
    Last edited by Anenja; 25th February 2013 at 09:50.

  13. #13
    Join Date
    Sep 2011
    Posts
    1,241
    Thanks
    3
    Thanked 127 Times in 126 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: QThread, moveToThread question

    this would be better.
    Qt Code:
    1. //create a worker and wait for its result
    2. QThread t1 = new QThread();
    3. Worker1 *worker = new Worker1("params for some work");
    4. worker->moveToThread(t1)
    5. // connect the worker with its finished signal, an start new worker with the result
    6. connect(t1, SIGNAL(started), worker, SLOT(startWork());
    7. connect(worker, SIGNAL(finished()), this, SLOT(worker1FinishedSlotStartWorker2WiththeNewResult());
    8. t1->start();
    To copy to clipboard, switch view to plain text mode 

    I am concerned about how you will pass the new result to worker2 in this example, though.
    If you have a problem, CUT and PASTE your code. Do not retype or simplify it. Give a COMPLETE and COMPILABLE example of your problem. Otherwise we are all guessing the problem from a fabrication where relevant details are often missing.

  14. #14
    Join Date
    Feb 2013
    Posts
    19
    Thanks
    4
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QThread, moveToThread question

    amleto

    I am concerned about how you will pass the new result to worker2 in this example, though.
    I just could give the finished signal a QString parameter and pass this to the destiny slot...

    What i dont really understand is this:
    Qt Code:
    1. // All the membervars which was created in the cTor without the (this)parent wont be moved to the new thread right?
    2. // that mean for example: membervar in the header file: int m_Test ;
    3. // cTor (cpp file) -> m_Test = 5; or in the init list m_test(5)
    4. QObject *obj = new QObject;
    5. obj->moveToThread(&t1);
    To copy to clipboard, switch view to plain text mode 

    So if i create membervars and use movetoThread -> must i set the parent to all my membervars (all who inherit qobject) to the currentclass (this)?
    Cause if i dont do this, the membervars are created in the mainthread for e.g and wont be moved to the new thread, so this maybe a problem right?
    If i use Threads without subclassing, i have to take care "where" i run the methods of the object, that mean if i am not in the right thread i have to run the methods via connect().(they have to be a slot then)
    I read s.th about QMetaObject::invoke.
    Qt Code:
    1. //the current thread is not the workerThread so calling this way of the slot is safe?
    2. QMetaObject::invokeMethod(pWorkersender, "slotName",Qt::AutoConnection); //instead pWorkersender->slotName()
    To copy to clipboard, switch view to plain text mode 
    Is this use of invokeMethod threadsafe? that mean can i call this way a slot without being afraid of getting problems?

    Thanks again for all ur help, really great answers!

  15. #15
    Join Date
    Sep 2011
    Posts
    1,241
    Thanks
    3
    Thanked 127 Times in 126 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: QThread, moveToThread question

    "So if i create membervars and use movetoThread -> must i set the parent to all my membervars (all who inherit qobject) to the currentclass (this)?"
    Yes.

    "Cause if i dont do this, the membervars are created in the mainthread for e.g and wont be moved to the new thread, so this maybe a problem right?"
    Yes.

    'invokeMethod' doesn't make something that isn't thread safe, thread safe. Using invokeMethod will make sure a slot is executed in its class instance's thread.

    So yes, there is a difference between
    QMetaObject::invokeMethod(pWorkersender, "slotName",Qt::AutoConnection); // slotname will be run in pworkersender's thread.
    and
    instead pWorkersender->slotName(); // slotname will be run in the current thread.

    This is totally different to something being 'thread safe'.
    If you have a problem, CUT and PASTE your code. Do not retype or simplify it. Give a COMPLETE and COMPILABLE example of your problem. Otherwise we are all guessing the problem from a fabrication where relevant details are often missing.

  16. The following user says thank you to amleto for this useful post:

    Anenja (27th February 2013)

  17. #16
    Join Date
    Feb 2013
    Posts
    19
    Thanks
    4
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QThread, moveToThread question

    amleto
    So yes, there is a difference between
    QMetaObject::invokeMethod(pWorkersender, "slotName",Qt::AutoConnection); // slotname will be run in pworkersender's thread.
    and
    instead pWorkersender->slotName(); // slotname will be run in the current thread.

    This is totally different to something being 'thread safe'.
    Thanks again.

    I will try to use your hints and make a simple application which is hopefully better than the first one

    Anenja

  18. #17
    Join Date
    Feb 2013
    Posts
    19
    Thanks
    4
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QThread, moveToThread question

    To complete this, just a final simple example of using movetothread.

    simple worker.h:
    Qt Code:
    1. class Worker : public QObject {
    2. Q_OBJECT
    3.  
    4. public:
    5. Worker();
    6. ~Worker();
    7.  
    8. public slots:
    9. void process();
    10.  
    11. signals:
    12. void finished();
    13.  
    14. private:
    15. };
    To copy to clipboard, switch view to plain text mode 
    worker.cpp
    Qt Code:
    1. //
    2. Worker::Worker() {
    3. //the parent of the membervars should be (this). that they will be correctly moved to the new thread
    4. }
    5.  
    6. void Worker::process() {
    7. qDebug("Hello World!");
    8. emit finished();
    9. }
    To copy to clipboard, switch view to plain text mode 

    use in widget/main class
    Qt Code:
    1. QThread* thread = new QThread;
    2. Worker* worker = new Worker();
    3. worker->moveToThread(thread);
    4. connect(thread, SIGNAL(started()), worker, SLOT(process()));
    5. //quits the event loop if a loop exists
    6. connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
    7. //deletes the worker object when the object is finished
    8. connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
    9. //deletes the thread when finished (of the thread) is emitted
    10. connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
    11. //emits the process slot
    12. thread->start();
    To copy to clipboard, switch view to plain text mode 

    I hope this use of movetothread is right, if not pls give me a hint...


    Added after 1 7 minutes:


    a nice post i found about threads, events and objects to make things more clear.

    http://qt-project.org/wiki/Threads_Events_QObjects
    Last edited by Anenja; 6th March 2013 at 11:01.

Similar Threads

  1. Replies: 11
    Last Post: 12th September 2012, 16:25
  2. Replies: 1
    Last Post: 4th September 2012, 14:13
  3. Replies: 2
    Last Post: 17th March 2011, 13:30
  4. QThread Question
    By ionutdanila in forum Newbie
    Replies: 7
    Last Post: 6th January 2011, 07:23
  5. basic qthread question
    By zl2k in forum Qt Programming
    Replies: 2
    Last Post: 9th September 2008, 21:43

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
  •  
Qt is a trademark of The Qt Company.