Page 2 of 2 FirstFirst 12
Results 21 to 39 of 39

Thread: Using QTimer in a QThread

  1. #21
    Join Date
    Nov 2010
    Posts
    315
    Thanked 53 Times in 51 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows Symbian S60 Maemo/MeeGo

    Default Re: Using QTimer in a QThread

    Maybe we misunderstand each-other. I'm trying to proof that thread shouldn't be moved to itself!
    Here is test code (stupid example but it works):
    Qt Code:
    1. #include <QThread>
    2. #include <QApplication>
    3. #include <QPushButton>
    4. #include <QTimer>
    5.  
    6. int main(int argCount, char* args[])
    7. {
    8. QApplication app(argCount, args);
    9.  
    10. QPushButton button("Start");
    11. QThread thread;
    12. QTimer timer;
    13. timer.setInterval(2000);
    14. timer.moveToThread(&thread);
    15. // thread.moveToThread(&thread); // this shouldn't be done
    16.  
    17. QObject::connect(&button, SIGNAL(clicked()),
    18. &thread, SLOT(start()));
    19.  
    20. QObject::connect(&button, SIGNAL(clicked()),
    21. &timer, SLOT(start()));
    22.  
    23. QObject::connect(&timer, SIGNAL(timeout()),
    24. qApp, SLOT(quit()));
    25.  
    26. button.show();
    27. app.exec();
    28. thread.exit();
    29. thread.wait(1000);
    30.  
    31. return 0;
    32. }
    To copy to clipboard, switch view to plain text mode 
    Program terminates after 2 second push button was pressed.
    Uncomment line 15 and program will not terminate 2 seconds after button was pressed you have a dead lock (checked on Ubuntu 10.04).

  2. #22
    Join Date
    Jan 2009
    Location
    Germany
    Posts
    387
    Thanks
    101
    Thanked 15 Times in 15 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Using QTimer in a QThread

    @wysota

    As usually, you state a radical opinion in a radical way. I'm curious what your approach would be to solve the task as stated above, that a steady high frequency communication (100Hz) has to be maintained while the CPU can be potentially maxed out at times with other tasks. RTOS is not an option, the target OS is Windows. Maybe it's a useful piece of information that one iteration of the communication takes between 2 and 3 milliseconds and it barely needs any CPU, since most of it is I/O time.

    Another advantage I see in threads is that often there is more than one core and while one core is struggling with the gui, the other core can still maintain the steady communication frequency. This would not be possible with only one process.

  3. #23
    Join Date
    Feb 2007
    Location
    Karlsruhe, Germany
    Posts
    469
    Thanks
    17
    Thanked 90 Times in 88 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Using QTimer in a QThread

    Hello Cruz,

    I'm running several 1-2ms precise threads under windows. What significantly improved matters is to lock the threads to specific cpu cores. By default windows "pushes them around" quite a bit, with negative influence on timing precision.

    Qt Code:
    1. #ifdef Q_WS_WIN
    2. # include "windows.h"
    3. #endif
    4.  
    5. #ifdef Q_OS_UNIX
    6. # include "unistd.h"
    7. # include "sys/syscall.h"
    8. # include <sys/types.h>
    9. # include <sys/time.h>
    10. # include <sys/statfs.h>
    11. # include <stdio.h>
    12. # include <sched.h>
    13. #endif
    14.  
    15. void QntsHPC::setCpuAffinityMask(quint32 coreMask)
    16. {
    17. // check if there are multiple cores at all
    18. if (QThread::idealThreadCount() > 1)
    19. {
    20. # ifdef Q_OS_WIN
    21. SetThreadAffinityMask(GetCurrentThread(),coreMask);
    22. # endif
    23. # ifdef Q_OS_UNIX
    24. //sched_setaffinity(gettid());
    25. int proc_num = (int)(long)coreMask;
    26. cpu_set_t set;
    27. CPU_ZERO( &set );
    28. CPU_SET( proc_num, &set );
    29. sched_setaffinity( syscall(SYS_gettid), sizeof( cpu_set_t ), &set );
    30. # endif
    31. }
    32. }
    To copy to clipboard, switch view to plain text mode 
    The mask is a bit-vector, see documentation for SetThreadAffinityMask.

    You probably will need only a subset of the linux includes for this. But no matter, your target is windows anyway :->

    HIH

    Johannes

  4. The following user says thank you to JohannesMunk for this useful post:

    Cruz (13th April 2011)

  5. #24
    Join Date
    Jan 2006
    Location
    Munich, Germany
    Posts
    4,714
    Thanks
    21
    Thanked 418 Times in 411 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows

    Default Re: Using QTimer in a QThread

    @Marek:
    this is not a dead lock, but a blocking call which never returns.
    A dead lock is when two or more processes are each waiting for the other to release a resource, or more than two processes are waiting for resources in a circular chain.
    In your example, since your thread didn't start, it is not processing the events it got, or events have no where to go.

    When you perform a moveToThread on the QThread object, that is all you do - you move a QThread object to the thread it started (if it did start a new thread).
    I don't see for what it could be good, but you need to understand the implications.
    "shouldn't be done" is an assertion that is worth very little if you don't explain why, or under what conditions.

    The only thing I am not sure about in the way your example works, is, that since you didn't call start() on the thread, there should be no "other thread", thus I am not sure what moveToThread() does in a case where the thread didn't start.
    That is the only point I am not quite sure how the internals of moveToThead work.
    @wysota:
    If you are reading this maybe you can answer what happens if you move to a thread that hasn't been started yet?
    I don't have Qt here.
    Last edited by high_flyer; 13th April 2011 at 14:15.
    ==========================signature=============== ==================
    S.O.L.I.D principles (use them!):
    https://en.wikipedia.org/wiki/SOLID_...iented_design)

    Do you write clean code? - if you are TDD'ing then maybe, if not, your not writing clean code.

  6. #25
    Join Date
    Jan 2009
    Location
    Germany
    Posts
    387
    Thanks
    101
    Thanked 15 Times in 15 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Using QTimer in a QThread

    @Johannes

    Thanks, I will try this! Did you evaluate how this technique works on Linux? While I am currently bound to Windows, my long term goal is to write something that works on both, Windows and Linux.
    Last edited by Cruz; 13th April 2011 at 12:19.

  7. #26
    Join Date
    Feb 2007
    Location
    Karlsruhe, Germany
    Posts
    469
    Thanks
    17
    Thanked 90 Times in 88 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Using QTimer in a QThread

    I measured the min/max/stddev of QThread::msleep intervals with the performance counter only under windows. I did not run the same tests on linux, because on my dev-machine it runs only virtually. But timing critical network connections between the virtual linux machine and other computers in the network seemed to work with good latencies, so I stopped tweaking.

    Be aware, that if you use only msleep and no timers with intervals smaller than 20ms you will have to increase the windows timer resolution for msleep to work correctly.

    See: http://www.qtcentre.org/threads/4031...340#post185340

    Johannes

  8. #27
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Using QTimer in a QThread

    Quote Originally Posted by high_flyer View Post
    Common witek, so what are you saying?
    You should not implement tasks that need time resolutions in ms range in non RTOS?
    I would say you should not aim to have precise timing on a system that can't give it to you.

    I am sure you, just as I have, made many such usages of threads that are "real time like" under windows/linux.
    There is a difference between real-time-like and expectations to have a slot called at exactly 10ms intervals. I'd say such expectations are not required in most cases and there using a regular system is fine. I would like to know why OP wants to have precisely 10ms intervals.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  9. #28
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Using QTimer in a QThread

    Quote Originally Posted by Cruz View Post
    I'm curious what your approach would be to solve the task as stated above, that a steady high frequency communication (100Hz) has to be maintained while the CPU can be potentially maxed out at times with other tasks.
    I would use a real time operating system or rethink my design.

    RTOS is not an option, the target OS is Windows.
    If it's not an option then just forget it and do something that doesn't require such rigid timing. If you can live with your app working properly "most of the time" or "sometimes" then just go ahead and keep your current approach. Just don't be surprised that if your system decides to do something besides scheduling your thread (say... defragment your harddisk) you will loose your "steady pace". People use real-time operating systems not because they are fun to use but because they are required to reach their goals. On a non-RT OS there is simply no way to force your OS to wake you up at constant intervals. You can use multimedia timers, bind process to a cpu or do anything else you want but this will give you no guarantees. You will be "close to 10ms" "usually" or even "most of the times" but not "always". If you can live with that then go ahead. But if you can live with that then maybe you don't need it after all.

    If your robot was performing some kind of surgery or space exploration-thingy I would surely not put my life in its hands if it required time guarantees and you were using regular Windows to obtain it.

    Another advantage I see in threads is that often there is more than one core and while one core is struggling with the gui, the other core can still maintain the steady communication frequency. This would not be possible with only one process.
    Unless you have more cores than processes running in your system this is completely meaningless in this particular situation.

    Quote Originally Posted by highflyer
    @wysota:
    If you are reading this maybe you can answer what happens if you move to a thread that hasn't been started yet?
    I don't have Qt here.
    Nothing happens. It (the object in question) can't process events (including slots) until the thread event loop is started. Similarily it can't process events (and slots) after the thread event loop is stopped. Besides this is just bad design. It's like you were driving a car using remote control sitting in the driver's seat of the very same car.
    Last edited by wysota; 13th April 2011 at 23:00.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  10. #29
    Join Date
    Jan 2006
    Location
    Munich, Germany
    Posts
    4,714
    Thanks
    21
    Thanked 418 Times in 411 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows

    Default Re: Using QTimer in a QThread

    Nothing happens. It (the object in question) can't process events (including slots) until the thread event loop is started.
    This is clear, but its not what I asked.
    moveToThread() takes a QThread pointer.
    The QThread object it self does exist, and its thread affinity is the thread in which it was created.
    I would think that moveToThread() "moves" the calling object to the actual thread the QThread object started. (which is what happens if QThread created a thread)
    But if no thread has been started, where does moveToThread() move the object to? (as in Marek's examples).
    Does it mean that once an object has been 'movedToThread()' that it will "complete" the moving once the thread has been created with start()?
    Besides this is just bad design.
    Ofcourse, but I still would like to understand it.
    ==========================signature=============== ==================
    S.O.L.I.D principles (use them!):
    https://en.wikipedia.org/wiki/SOLID_...iented_design)

    Do you write clean code? - if you are TDD'ing then maybe, if not, your not writing clean code.

  11. #30
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Using QTimer in a QThread

    Quote Originally Posted by high_flyer View Post
    I would think that moveToThread() "moves" the calling object to the actual thread the QThread object started. (which is what happens if QThread created a thread)
    But if no thread has been started, where does moveToThread() move the object to? (as in Marek's examples).
    In reality what happens is that the object is checked for pending events and if such are found they are taken out of the event loop of the "old" thread and inserted into the event loop of the "new" thread. The event loop exists (it's actually an instance of QAbstractEventDispatcher that is keyed with a pointer to QThread) it's just not running. So the move suceeds.

    Does it mean that once an object has been 'movedToThread()' that it will "complete" the moving once the thread has been created with start()?
    More likely when you call QThread::exec(). But this doesn't change the fact that after the thread event loop stops and run() returns there is no way to call any slots in the QThread object since it lives in a thread that doesn't process events anymore (so it can't call slots) and you can't push the object to the main thread because there is no worker thread context anymore to invoke the push. Similarily you have no control over what happens before you start the thread event loop.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  12. #31
    Join Date
    Jan 2009
    Location
    Germany
    Posts
    387
    Thanks
    101
    Thanked 15 Times in 15 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Using QTimer in a QThread

    The discussion has drifted off here. The original question why a timer started in a thread appears to run in the main thread. And one of the issues pointed out (the reason for which is still unexplained!) is that a thread shouldn't handle it's own events.. A clean way to use a timer in a thread was suggested like this:

    Qt Code:
    1. class TestClass : QObject
    2. {
    3. Q_OBJECT
    4. public:
    5. TestClass(QObject *parent=0);
    6.  
    7. public slots:
    8. void tick();
    9. };
    10.  
    11. TestClass::TestClass(QObject *parent) : QObject(parent)
    12. {
    13. QTimer *t = new QTimer(this);
    14. connect(t, SIGNAL(timeout()), this, SLOT(tick()));
    15. }
    16.  
    17. void TestClass::tick()
    18. {
    19. qDebug() << currentThreadId() << "tick()";
    20. }
    21.  
    22. // and somewhere
    23. QThread *thread = new QThread(something);
    24. TestClass *object = new TestClass(); // can't pass parent!!!!!!
    25. object->moveToThread(thread);
    26. thread->start();
    To copy to clipboard, switch view to plain text mode 

    However, if not a QTimer, but a while and sleep method is used, this code changes to:

    Qt Code:
    1. class Thread : QThread
    2. {
    3. TestClass testClass;
    4. }
    5.  
    6. Thread::Thread()
    7. {
    8. testClass.moveToThread(this);
    9. start();
    10. }
    11.  
    12. Thread::run()
    13. {
    14. forever
    15. {
    16. testClass.tick();
    17. QApplication::processEvents();
    18. }
    19. }
    20.  
    21. main
    22. {
    23. Thread rhread;
    24. ... do mainy things...
    25. }
    To copy to clipboard, switch view to plain text mode 

    The problem I have with this construction is that now TestClass is buried inside the QThread wrapper. When signals needs to be emitted from main to TestClass, some kind of a hack needs to be used because TestClass is unknown in main. This is not the case, however, if TestClass IS a QThread and is moved to its own thread. So how can you solve this elegantly without moving the thread to itself?

  13. #32
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Using QTimer in a QThread

    You either expose a getter that fetches a pointer to the object in the thread class or you provide a setter to set the object before the thread is executed or you embed the thread object in the TestClass object instead of embedding the TestClass object inside the thread object.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  14. #33
    Join Date
    Jan 2009
    Location
    Germany
    Posts
    387
    Thanks
    101
    Thanked 15 Times in 15 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Using QTimer in a QThread

    Quote Originally Posted by wysota View Post
    ...or you embed the thread object in the TestClass object instead of embedding the TestClass object inside the thread object.
    But then how does the thread call the tick() method of TestClass?

  15. #34
    Join Date
    Jan 2009
    Location
    Germany
    Posts
    387
    Thanks
    101
    Thanked 15 Times in 15 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Using QTimer in a QThread

    For completeness, like this it works:

    Qt Code:
    1. class Thread : QThread
    2. {
    3. signals:
    4. void tickOut();
    5. }
    6.  
    7. Thread::Thread()
    8. {
    9. start();
    10. }
    11.  
    12. Thread::run()
    13. {
    14. forever
    15. {
    16. emit tickOut();
    17. QApplication::processEvents();
    18. msleep(10);
    19. }
    20. }
    21.  
    22. class TestClass
    23. {
    24. Thread thread;
    25.  
    26. public slots:
    27. void tickIn();
    28. }
    29.  
    30. TestClass::TestClass
    31. {
    32. moveToThread(&thread);
    33. connect(&thread, SIGNAL(tickOut()), this, SLOT(tickIn()));
    34. }
    To copy to clipboard, switch view to plain text mode 

    Is this ok? No hack or anything?

  16. #35
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Using QTimer in a QThread

    It's not fine. You have a static time delay which means your real delay depends on how long it takes processEvents() to complete its work. The delay should be dynamically adjusted or it should be done using a timer. I don't see how calling sleep would be better than using a timer.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  17. #36
    Join Date
    Jan 2009
    Location
    Germany
    Posts
    387
    Thanks
    101
    Thanked 15 Times in 15 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Using QTimer in a QThread

    The parameter to sleep is adjusted. I omitted it to simplify the code, because what I was asking about is if the construction is ok.
    I looked at the steadiness of the QTimer based approach and the dynamically adjusted sleep approach and found the latter to be smoother.

  18. #37
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Using QTimer in a QThread

    How did you "look" at it?
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  19. #38
    Join Date
    Jan 2009
    Location
    Germany
    Posts
    387
    Thanks
    101
    Thanked 15 Times in 15 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Using QTimer in a QThread

    I "looked" at it by "plotting" the iteration times produced by the dynamic sleep approach and the QTimer approach. I measured the iteration times using high performance counters on Windows. The following two plots show the different behaviors of the two approaches. Clearly, the QTimer based iterations are much more noisy.
    dynamicsleep.jpg qtimer.jpg

    I also "looked" at the effect of starting the thread in time critical instead of normal mode, and what happens if the cpu is stressed. The next plot shows the results of a series of 8 experiments. The 8 experiments are all combinations of dynamic sleep or QTimer, thread was started in time critical mode or not, and if the cpu was stressed or not. Red bars show dynamic sleep, blue bars show QTimers, each with mean and standard deviation "calculated" over 5 minutes runtime. I was aiming at an iteration time of 12 milliseconds. In the cpu stress experiments, both cores of my cpu were tortured by Prime95.
    threadplot2.jpg

  20. #39
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Using QTimer in a QThread

    How did you eliminate the influence of external conditions on the test you performed? Did you also do any stress testing? QTimer will show some variation because the resolution of timers used with it is usually greater than 1ms, especially on Windows. sleep() shouldn't suffer from such problems as it probably relies on capabilities of the scheduler. Also bear in mind both these approaches will fail if something (processEvents) occupies your app for the whole (or almost whole) desired interval or if something prevents the scheduler from running at the exact demanded point in time. You simply can't overcome this without RTOS.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


Similar Threads

  1. QTimer within QThread
    By Eos Pengwern in forum Qt Programming
    Replies: 6
    Last Post: 23rd February 2011, 20:00
  2. qthread / qtimer
    By Galen in forum Qt Programming
    Replies: 5
    Last Post: 17th April 2010, 22:57
  3. QThread and QTimer
    By sivrisinek in forum Qt Programming
    Replies: 4
    Last Post: 30th April 2009, 16:41
  4. QThread & QTimer
    By hosseinyounesi in forum Qt Programming
    Replies: 5
    Last Post: 13th April 2009, 08:22
  5. QTimer and QThread
    By TheKedge in forum Qt Programming
    Replies: 4
    Last Post: 21st September 2006, 14:52

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.