Results 1 to 11 of 11

Thread: QThreads and Windows Multimedia Timer

  1. #1
    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 QThreads and Windows Multimedia Timer

    Hello!

    I have a GUI and a worker thread. The worker thread is ticked periodically by a windows multimedia timer. I'm not using a QTimer because I need a higher precision. Now the problem is that I want to transfer data from the GUI to the worker thread in a thread safe manner using signals and slots. But the multimedia timer creates its own thread, so the worker loop is in a different thread than the event loop, where the slots are handled. I don't know how to solve this, please help. Here is the code:

    Qt Code:
    1. /////////////// The GUI class///////////////////
    2. class GUI
    3. {
    4. WorkerThread wt;
    5. Data data;
    6.  
    7. signals:
    8. dataOut(Data);
    9. }
    10.  
    11. GUI::GUI()
    12. {
    13. connect(this, SIGNAL(dataOut(Data)), &wt, SLOT(dataIn(Data)));
    14. wt.start();
    15. }
    16.  
    17. GUI::somewhere()
    18. {
    19. emit dataOut(data);
    20. qDebug() << QThread::currentThreadId() << "data emitted";
    21. }
    22.  
    23.  
    24. /////////////// The Worker Thread ///////////////////
    25. class WorkerThread : QThread
    26. {
    27. Data data;
    28. void tick();
    29.  
    30. public slots:
    31. dataIn(Data);
    32. }
    33.  
    34. WorkerThread::WorkerThread()
    35. {
    36. moveToThread(this);
    37. }
    38.  
    39. // This is the callback function of the windows media timer.
    40. void CALLBACK PeriodicCallback(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
    41. {
    42. WorkerThread* wt = (WorkerThread*)dwUser;
    43. wt->tick();
    44. }
    45.  
    46. // When the thread is started, I create the MM timer and start the event loop.
    47. void RobotControl::run()
    48. {
    49. // Set resolution to the minimum supported by the system.
    50. TIMECAPS tc;
    51. timeGetDevCaps(&tc, sizeof(TIMECAPS));
    52. timerRes = qMin(qMax(tc.wPeriodMin, (UINT) 0), tc.wPeriodMax);
    53. timeBeginPeriod(timerRes);
    54.  
    55. // Create the callback timer.
    56. timerId = timeSetEvent(12, 0, PeriodicCallback, (DWORD_PTR) this, 1);
    57.  
    58. // Start the event loop.
    59. exec();
    60. }
    61.  
    62. WorkerThread::tick()
    63. {
    64. use(data);
    65. qDebug() << QThread::currentThreadId() << "worker thread was ticked";
    66. }
    67.  
    68. WorkerThread::dataIn(Data d)
    69. {
    70. data = d;
    71. qDebug() << QThread::currentThreadId() << "data received";
    72. }
    To copy to clipboard, switch view to plain text mode 

    Now the output of this code is:
    0xaa8 worker thread was ticked
    0xaa8 worker thread was ticked
    0xaa8 worker thread was ticked
    0xb98 data emitted
    0x16e4 data received
    0xaa8 worker thread was ticked
    0xaa8 worker thread was ticked
    0xaa8 worker thread was ticked
    As you can see, there are three different threads. How can I achieve that the tick()s are executed on the same thread as the data slots?

  2. #2
    Join Date
    Mar 2011
    Location
    Hyderabad, India
    Posts
    1,882
    Thanks
    3
    Thanked 452 Times in 435 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows
    Wiki edits
    15

    Default Re: QThreads and Windows Multimedia Timer

    How can I achieve that the tick()s are executed on the same thread as the data slots?
    If you want to execute tick() in the same thread as dataIn() slot, then you mush use event loop, it is one of the event loop's feature to execute timer events (QTimer events) in the threads own context. But as you use separate thread for timer tick() it will not be possible to run tick() and dataIn() slot in same thread. As an alternate you can always share data between the tick() thread and dataIn() thread using a QMutex, something like this.

    Qt Code:
    1. class WorkerThread : QThread
    2. {
    3. Data data;
    4. QMutex dataMutex;
    5. void tick();
    6.  
    7. public slots:
    8. dataIn(Data);
    9. }
    10.  
    11. WorkerThread::tick()
    12. {
    13. dataMutex.lock();
    14. use(data);
    15. dataMutex.unLock();
    16. qDebug() << QThread::currentThreadId() << "worker thread was ticked";
    17. }
    18.  
    19. WorkerThread::dataIn(Data d)
    20. {
    21. dataMutex.lock();
    22. data = d;
    23. dataMutex.unLock();
    24. qDebug() << QThread::currentThreadId() << "data received";
    25. }
    To copy to clipboard, switch view to plain text mode 

    As you are using a native OS timer mechanism for precision reasons, it will better to use native mutex locking and unlocking mechanisms to maintain the precision, using QMutex might add some overhead.

  3. #3
    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: QThreads and Windows Multimedia Timer

    I'm sorry but a mutex is not an option, as it delays the timing of my worker thread. What I need is the timer and the dataIn() slot to run on the same thread.

  4. #4
    Join Date
    Mar 2011
    Location
    Hyderabad, India
    Posts
    1,882
    Thanks
    3
    Thanked 452 Times in 435 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows
    Wiki edits
    15

    Default Re: QThreads and Windows Multimedia Timer

    It is not possible, unless you use either event loop, or some kind of resource locking

  5. #5
    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: QThreads and Windows Multimedia Timer

    Event loop yes, there is already one in my original example. It's just not on the same thread as the timer. Can I somehow move my worker thread to the timer thread so that the event loop is processed there? Or can I somehow process the event loop in the tick() method? I tried to call QApplication:rocessEvents() there, but it didn't work.

  6. #6
    Join Date
    Mar 2011
    Location
    Hyderabad, India
    Posts
    1,882
    Thanks
    3
    Thanked 452 Times in 435 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows
    Wiki edits
    15

    Default Re: QThreads and Windows Multimedia Timer

    You can write you own event loop in the timer thread, using QEventLoop

  7. #7
    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: QThreads and Windows Multimedia Timer

    How can I implement a custom QEventLoop in my multimedia timer driven thread? I have tried creating my own QEventLoop and calling processEvents() on it with every iteration of the timer. But it doesn't do anything. Well, if I don't use the moveToThread() call in the code below, then the dataIn() connection is a direct one and the signal and the slot are executed on the same thread. If I do the moveToThread(), then the connection should be a queued one, but I guess it goes to the wrong thread. How can I tell Qt to handle the slot with the provessEvents() call of my own QEventLoop?


    Qt Code:
    1. class WorkerThread : QThread
    2. {
    3. QEventLoop* eventLoop; // my custom event loop
    4. Data data;
    5. void tick();
    6.  
    7. public slots:
    8. dataIn(Data);
    9. }
    10.  
    11. WorkerThread::WorkerThread()
    12. {
    13. moveToThread(this); // optional
    14. }
    15.  
    16. // This is the callback function of the windows media timer.
    17. // It just calls tick() of my worker thread.
    18. void CALLBACK PeriodicCallback(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
    19. {
    20. WorkerThread* wt = (WorkerThread*)dwUser;
    21. wt->tick();
    22. }
    23.  
    24. // When the thread is started, I create the MM timer and have it call PeriodicCallback().
    25. void RobotControl::start()
    26. {
    27. // Set resolution to the minimum supported by the system.
    28. TIMECAPS tc;
    29. timeGetDevCaps(&tc, sizeof(TIMECAPS));
    30. timerRes = qMin(qMax(tc.wPeriodMin, (UINT) 0), tc.wPeriodMax);
    31. timeBeginPeriod(timerRes);
    32.  
    33. // Create the callback timer.
    34. timerId = timeSetEvent(12, 0, PeriodicCallback, (DWORD_PTR) this, 1);
    35. }
    36.  
    37. WorkerThread::tick()
    38. {
    39. // Initialize and call the event loop.
    40. static bool eventLoopInitialized = false;
    41. if (!eventLoopInitialized)
    42. {
    43. eventLoopInitialized = true;
    44. eventLoop = new QEventLoop();
    45. }
    46. else
    47. {
    48. //QApplication::processEvents();
    49. eventLoop->processEvents(); // not sure which one to call
    50. }
    51.  
    52. use(data);
    53. qDebug() << QThread::currentThreadId() << "worker thread was ticked";
    54. }
    55.  
    56. // I would like this slot to be handled on the same thread as tick().
    57. WorkerThread::dataIn(Data d)
    58. {
    59. data = d;
    60. qDebug() << QThread::currentThreadId() << "data received";
    61. }
    To copy to clipboard, switch view to plain text mode 

  8. #8
    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: QThreads and Windows Multimedia Timer

    Is this question too hard or too stupid?

  9. #9
    Join Date
    Mar 2011
    Location
    Hyderabad, India
    Posts
    1,882
    Thanks
    3
    Thanked 452 Times in 435 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows
    Wiki edits
    15

    Default Re: QThreads and Windows Multimedia Timer

    Quote Originally Posted by Santosh Reddy
    You can write you own event loop in the timer thread, using QEventLoop
    I might have misguided you with this reply, sorry for that. Looks like QEventLoop will work only with QThread (or with Qt Created threads), not with native threads. (AFAIK)

    As I see, as said earlier, you need to have some kind to native thread synchronization mechanism, Qt communication may not work with native threads. Even if there were a way to synchronize, I am sure you should compromise on the timing, to some extent.

    As I don't know your application requirements, I cannot suggest any workarounds either.

    Quote Originally Posted by Cruz
    I'm sorry but a mutex is not an option, as it delays the timing of my worker thread. What I need is the timer and the dataIn() slot to run on the same thread.
    If mutex is not an option, then signals & slots also are not an option, as signals & slots internally use thread blocking using mutex a bunch of times.
    Last edited by Santosh Reddy; 26th July 2011 at 02:43.

  10. #10
    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: QThreads and Windows Multimedia Timer

    Alright. Thank you for the insight, I will see how I can make it work with mutexing.

    However, your reply makes me wonder about the justification for the existence of QEventLoop. Since QThreads already come with their own event loop and QEventLoop only works with QThread, what's the use case of QEventLoop?

  11. #11
    Join Date
    Mar 2011
    Location
    Hyderabad, India
    Posts
    1,882
    Thanks
    3
    Thanked 452 Times in 435 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows
    Wiki edits
    15

    Default Re: QThreads and Windows Multimedia Timer

    QEventLoop can be used in a thread, when you want to implement a custom exec() like funtionality, you can at any time during the thread execution create a QEventLoop and process the required events locally, and then then continue with your job. I guess there is no way to exit the inbuilt eventloop from with in the same thread, in such cases QEventLoop may be handy.

Similar Threads

  1. timer problem(timer does not work)
    By masuk in forum Newbie
    Replies: 6
    Last Post: 14th February 2011, 05:00
  2. Qt multimedia on Linux (pulseaudio)
    By janK in forum Newbie
    Replies: 3
    Last Post: 15th May 2010, 20:52
  3. Replies: 0
    Last Post: 29th October 2009, 19:20
  4. Using QT for a CBT/CBL Multimedia Application Authoring
    By bglazier in forum Qt Programming
    Replies: 4
    Last Post: 17th April 2009, 07:47
  5. Qt multimedia browser plug-in
    By MartinS in forum Qt Programming
    Replies: 0
    Last Post: 28th January 2009, 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
  •  
Qt is a trademark of The Qt Company.