Results 1 to 8 of 8

Thread: How to cleanup timers properly?

  1. #1
    Join Date
    Feb 2006
    Location
    Oslo, Norway
    Posts
    6,264
    Thanks
    36
    Thanked 1,519 Times in 1,389 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows Symbian S60 Maemo/MeeGo

    Default How to cleanup timers properly?

    I am using a thread with an external event loop. This thread explains why: Postin custom events to a subclass of QThread
    Now I've got a nasty problem with cleaning up timers running in the event loop class.
    I've got tons of messages saying:
    "QObject::killTimer: timers cannot be stopped from another thread"
    when closing the application.

    Example code snippets below illustrate the problem:

    An example event loop class:
    Qt Code:
    1. class MyEventLoop : public QEventLoop
    2. {
    3. public:
    4. MyEventLoop(QObject* parent = 0) : QEventLoop(parent)
    5. {
    6. timers << startTimer(1000);
    7. timers << startTimer(2500);
    8. }
    9.  
    10. ~MyEventLoop()
    11. {
    12. // this basically gets never called since the output is flooded by thousands of lines saying:
    13. // "QObject::killTimer: timers cannot be stopped from another thread"
    14. // and i am forced to kill the application process
    15. foreach (int id, timers)
    16. killTimer(id);
    17. }
    18.  
    19. protected:
    20. void timerEvent(QTimerEvent* event)
    21. {
    22. qDebug() << "ID: " << event->timerId();
    23. }
    24.  
    25. private:
    26. QList<int> timers;
    27. };
    To copy to clipboard, switch view to plain text mode 

    An example thread class using an "external" event loop:
    Qt Code:
    1. class MyThread : public QThread
    2. {
    3. public:
    4. MyThread(QObject* parent = 0) : QThread(parent) {}
    5.  
    6. ~MyThread()
    7. {
    8. myeventloop->quit();
    9. // i have also tried "delete myeventloop;"
    10. myeventloop->deleteLater();
    11. }
    12.  
    13. protected:
    14. void run()
    15. {
    16. myeventloop = new MyEventLoop;
    17. myeventloop->exec();
    18. }
    19.  
    20. private:
    21. MyEventLoop* myeventloop;
    22. };
    To copy to clipboard, switch view to plain text mode 

    An example widget managing a thread like above:
    Qt Code:
    1. class ThreadWidget : public QTextEdit
    2. {
    3. public:
    4. ThreadWidget(QWidget* parent = 0) : QTextEdit(parent)
    5. {
    6. mythread = new MyThread(this);
    7. mythread->start();
    8. }
    9.  
    10. ~ThreadWidget()
    11. {
    12. // as far as i understand, quit() would have no effect
    13. // because the thread is running an external event loop
    14. mythread->terminate();
    15. }
    16.  
    17. private:
    18. MyThread* mythread;
    19. };
    To copy to clipboard, switch view to plain text mode 
    J-P Nurmi

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

    Default Re: How to cleanup timers properly?

    Only QThread::run() is executed in a new thread. The rest belongs to a the thread where QThread instance was created (in your case, the GUI thread).

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

    jpn (4th July 2006)

  4. #3
    Join Date
    Feb 2006
    Location
    Oslo, Norway
    Posts
    6,264
    Thanks
    36
    Thanked 1,519 Times in 1,389 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows Symbian S60 Maemo/MeeGo

    Default Re: How to cleanup timers properly?

    Ok, maybe it wasn't so good idea to use an external event loop after all. I decided to revise the code a bit so that the thread runs it's own event loop and there is just some object running timers instead of an event loop object. the object is instantiated before entering to the event loop and deleted right after returning from the event loop.

    Qt Code:
    1. void MyThread::run()
    2. {
    3. myobject = new MyObject;
    4. exec();
    5. delete myobject;
    6. }
    To copy to clipboard, switch view to plain text mode 

    MyObject cleans up it's timers in it's destructor and the widget managing the thread calls quit() and wait() for the thread in it's destructor. Sending custom events, cleaning up timers and everything else works now flawlessly.
    J-P Nurmi

  5. #4
    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: How to cleanup timers properly?

    Your design is problematic since you are mixing view and functionality.
    (Like your ThreadWidget which is a QTextEdit that has functionality, with threads even!)
    This is in general is a bad practice since it makes your code inflexible and it breaks encapsulation (which is an OOP principle).
    The GUI should be used for the view and let the work be done in functional modules.
    This will also make the whole thread problems you have much simpler.

  6. #5
    Join Date
    Feb 2006
    Location
    Oslo, Norway
    Posts
    6,264
    Thanks
    36
    Thanked 1,519 Times in 1,389 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows Symbian S60 Maemo/MeeGo

    Default Re: How to cleanup timers properly?

    Quote Originally Posted by high_flyer
    Your design is problematic since you are mixing view and functionality.
    (Like your ThreadWidget which is a QTextEdit that has functionality, with threads even!)
    This is in general is a bad practice since it makes your code inflexible and it breaks encapsulation (which is an OOP principle).
    The GUI should be used for the view and let the work be done in functional modules.
    This will also make the whole thread problems you have much simpler.
    The architecture of the real application is very much more complicated than the supplied dummy example. There is some kind of network/worker thread doing it's work underneath. There must be some mechanism for the thread to know when to do and what. I don't find it so bad design if the application's main widget manages the thread by starting/quiting it in the beginning/end of the widget's life time, and by either emitting signals or posting custom events to it..

    The actual problem was very simple. You cannot emit signals or post events ACROSS THREAD to a QThread descendant object. When using signals and slots, the slot will be executed in the main thread and when posting event's, the event gets posted in the main event loop. The correct way is to instantiate an object in QThread::run() and emit signals and/or post events directly to that object.
    J-P Nurmi

  7. #6
    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: How to cleanup timers properly?

    jpn:
    My comment about the design in the code you posted is not directly connected to the problem you raised with the cross thread communication.
    And since its a design issue, it really has nothing to do with the size of the code, but on it functionality.
    Its a bad practice to mix view and functionality.
    It is good practise to use encapsulation when programming C++ (OOP).
    I offered it as a constructive comment, its ok if you don't agree with it.
    And, it *could* be that with a correct design your inter thread communication problem would be solved or easer to handle.

    While I don't mind if you agree with my above comment I do mind the following since its missleading others:
    You cannot emit signals or post events ACROSS THREAD to a QThread descendant object.
    This is not true.
    From the docs:
    It is important to keep in mind that the event loop may be delivering events to your QObject subclass while you are accessing the object from another thread.
    And :
    When using signals and slots, the slot will be executed in the main thread and when posting event's, the event gets posted in the main event loop.
    No - when you send signal across threads its execution depends on what kind of a connection you made:
    If its a direct connetion the slot will be executed in the thread in which the signal was emmited, that does not have to be the main thread.
    If the connection you made is a qued connection then the slot will be executed in the thread in which the object that has the slot lives in, again, does not have to be the main thread.

    I would advise you to read the chapter about threading in the Qt4 docs.

  8. #7
    Join Date
    Feb 2006
    Location
    Oslo, Norway
    Posts
    6,264
    Thanks
    36
    Thanked 1,519 Times in 1,389 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows Symbian S60 Maemo/MeeGo

    Default Re: How to cleanup timers properly?

    Quote Originally Posted by high_flyer
    No - when you send signal across threads its execution depends on what kind of a connection you made:
    If its a direct connetion the slot will be executed in the thread in which the signal was emmited, that does not have to be the main thread.
    The issue is not about the connection type. I have used a queued connection. The "problem" is object's owner thread. As if you know, queued signals are delivered as events underhood. If the QThread object lives in the main thread as well, the stuff gets queued but later sent directly, not posted across thread. One could easily believe that queued signals and/or posted custom events would get delivered to the qthread object's own event loop. But that is not the case and I'm glad to know it now.

    Quote Originally Posted by high_flyer
    If the connection you made is a qued connection then the slot will be executed in the thread in which the object that has the slot lives in, again, does not have to be the main thread.
    You are missing the point. I was talking about two objects both living in main thread. Regardless of fact that one of the objects is a QThread object and the connection is queued, the slot will be executed in the main thread since that's where the QThread object lives in.

    Go ahead and test it by yourself:
    http://qtnode.net/pastebin/800
    J-P Nurmi

  9. #8
    Join Date
    Feb 2006
    Location
    Oslo, Norway
    Posts
    6,264
    Thanks
    36
    Thanked 1,519 Times in 1,389 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows Symbian S60 Maemo/MeeGo

    Default Re: How to cleanup timers properly?

    Quote Originally Posted by high_flyer
    jpn:
    My comment about the design in the code you posted is not directly connected to the problem you raised with the cross thread communication.
    And since its a design issue, it really has nothing to do with the size of the code, but on it functionality.
    Its a bad practice to mix view and functionality.
    It is good practise to use encapsulation when programming C++ (OOP).
    I offered it as a constructive comment, its ok if you don't agree with it.
    And, it *could* be that with a correct design your inter thread communication problem would be solved or easer to handle.
    I simply couldn't resist to comment this furthermore. You are just judging pretty hard without knowing anything about the subject..

    What if everything shown in the GUI is highly dependant on a network flow receiving tons of data items all the time. The network flow must be adjusted once in a while so that only required data items are ordered, otherwise the connection would get obstructed. Mostly anything done by the user causes also a change in the network flow. It's not that I'm having any freaking widget with a direct pointer to some thread object. There is a separate module handling all the network stuff. As I said, the example was just to illustrate the inter-thread communication problem I had.
    J-P Nurmi

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.