Results 1 to 10 of 10

Thread: Trouble while destroying thread

  1. #1
    Join Date
    Aug 2012
    Posts
    3
    Thanks
    1
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Unhappy Trouble while destroying thread

    Hello everyone,

    I'm not really used to using Qt, but for my work, I'v to do with it . I 've tried to make a generic thread Worker for my actions in multithreaded application. Here is my code

    ThreadWorker.h
    Qt Code:
    1. #ifndef _THREADWORKER_H_
    2. #define _THREADWORKER_H_
    3.  
    4. #include "QtCore/qobject.h"
    5. #include "QtCore/qthread.h"
    6. #include "QtCore/qtimer.h"
    7.  
    8. class ThreadWorker : public QObject
    9. {
    10. Q_OBJECT
    11.  
    12. private:
    13. int _frequency;
    14. QTimer _timer;
    15.  
    16. public:
    17. ThreadWorker(int frequency = 300);
    18. ~ThreadWorker();
    19.  
    20. /*!
    21. \brief Create a worker which call the specified slot in th specified thread
    22. \param thread The thread to use
    23. \param source The object which contains the slot to use
    24. \param slot The slot to use
    25. */
    26. void createWorker(QThread *thread, const QObject* source, const char *slot);
    27.  
    28. /*!
    29. \brief Sets the call frequency for the threaded method
    30. \param frequency Frequency in millsecond (default value: 300ms)
    31. */
    32. void setFrequency(int frequency);
    33.  
    34.  
    35. private slots:
    36. void start();
    37. void stop();
    38.  
    39. public slots:
    40. /*!
    41. \brief a slot to indicates the end of our current work
    42. */
    43. void terminate();
    44.  
    45. signals:
    46. void finished();
    47. };
    48.  
    49. #endif
    To copy to clipboard, switch view to plain text mode 

    ThreadWorker.cpp
    Qt Code:
    1. #include "ThreadWorker.h"
    2.  
    3. ThreadWorker::ThreadWorker(int frequency): _frequency(frequency), _timer(this)
    4. {}
    5.  
    6. ThreadWorker::~ThreadWorker()
    7. {
    8. terminate();
    9. }
    10.  
    11. void ThreadWorker::createWorker(QThread *thread, const QObject* source, const char *slot)
    12. {
    13. connect(&_timer, SIGNAL(timeout()), source, slot, Qt::DirectConnection);
    14.  
    15. connect(thread, SIGNAL(started()), this, SLOT(start()), Qt::DirectConnection);
    16. connect(this, SIGNAL(finished()), thread, SLOT(quit()), Qt::DirectConnection);
    17. connect(this, SIGNAL(finished()), this, SLOT(stop()), Qt::DirectConnection);
    18.  
    19. moveToThread(thread);
    20. }
    21.  
    22. void ThreadWorker::setFrequency(int frequency)
    23. {
    24. _frequency = frequency;
    25. }
    26.  
    27. void ThreadWorker::start()
    28. {
    29. _timer.setInterval(_frequency);
    30. _timer.start();
    31. }
    32.  
    33. void ThreadWorker::stop()
    34. {
    35. if(_timer.isActive())
    36. {
    37. _timer.stop();
    38. }
    39. }
    40.  
    41. void ThreadWorker::terminate()
    42. {
    43. if(_timer.isActive())
    44. {
    45. emit finished();
    46. }
    47. }
    To copy to clipboard, switch view to plain text mode 

    And here is the code which use the ThreadWorker
    Qt Code:
    1. #include "ThreadWorker.h"
    2.  
    3. class MyObject : public QObject
    4. {
    5.  
    6. Q_OBJECT
    7.  
    8. private
    9. QThread _thread;
    10. ThreadWorker _worker;
    11.  
    12. public:
    13. MyObject();
    14. ~MyObject();
    15. void start();
    16. void stop();
    17.  
    18. public slots:
    19. void process();
    20. };
    21.  
    22. MyObject::MyObject(): _thread(this)
    23. {}
    24.  
    25. MyObject::~MyObject()
    26. {
    27. if(_thread.isRunning())
    28. {
    29. _worker.terminate();
    30. _thread.wait(500);
    31. }
    32. }
    33.  
    34. void MyObject::start()
    35. {
    36. if(_thread.isRunning())
    37. {
    38. return;
    39. }
    40.  
    41. _worker.createWorker(&_thread, this, SLOT(process()));
    42.  
    43. _thread.start();
    44. }
    45.  
    46. void MyObject::process()
    47. {
    48. //do something
    49. }
    50.  
    51. void MyObject::stop()
    52. {
    53. _worker.terminate();
    54. }
    To copy to clipboard, switch view to plain text mode 

    I run this code in unit tests with QTest library and I use the macro QTEST_MAIN.
    The execution seems fine until the following error:
    Program: …
    Module: 4.7.4
    File: global\qglobal.cpp
    Line:

    ASSERT failure in QCoreApplication::sendEvent: “Cannot send events to objects owned by a different thread. Current thread 3f6a90.
    Receiver ‘’ (of type ‘ThreadWorker’) was created in thread 12ef5c”, file kernel\qcoreapplication.cpp, line...
    I do not really see where it comes from :/. Only thing is that this does not occur if I do not put this line moveToThread (thread), however, in this case, the slot process() is never called.

    Does anyone have any idea what I am doing wrong?

    Thank you in advance for any help you can provide me

    ps: Sorry if my english is not correct :/

  2. #2
    Join Date
    Oct 2009
    Posts
    483
    Thanked 97 Times in 94 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Trouble while destroying thread

    If I read your code correctly, something is wrong in the logic of the program: the MyObject instance does not live in the new thread but you try to force its slots to be executed there by a direct connection. You must not do that. The MyObject instance must live in the worker thread. If what you want to achieve is to execute MyObject::process() periodically in a worker thread, just move a MyObject and a QTimer there.

  3. #3
    Join Date
    Aug 2012
    Posts
    3
    Thanks
    1
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Trouble while destroying thread

    Thank you for your response Yeye_olive. I've tried to do this in the creatWorker() method:

    Qt Code:
    1. moveToThread(thread);
    2. source->moveToThread(thread);
    To copy to clipboard, switch view to plain text mode 

    But the error is still the same :/

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

    Default Re: Trouble while destroying thread

    did you get rid of all the DirectConnection specifiers yet?
    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.

  5. #5
    Join Date
    Oct 2009
    Posts
    483
    Thanked 97 Times in 94 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Trouble while destroying thread

    By doing source->moveToThread(thread) you also move source's children, including the QThread, which is a common mistake. I suggest you rethink a bit the architecture of your solution. Here is a rough suggestion:
    Qt Code:
    1. class Manager {
    2. public:
    3. Manager();
    4. ~Manager();
    5. void add(QObject *o, const char *method);
    6. private:
    7. QThread thread;
    8. QTimer timer;
    9. };
    10.  
    11. Manager::Manager() {
    12. timer.setInterval(42000);
    13. QObject::connect(&thread, SIGNAL(started()), &timer, SLOT(start()));
    14. timer.moveToThread(&thread);
    15. thread.start();
    16. }
    17.  
    18. Manager::~Manager() {
    19. thread.quit();
    20. thread.wait();
    21. }
    22.  
    23. void Manager::add(QObject *o, const char *method) {
    24. QObject::connect(&timer, SIGNAL(timeout), o, method);
    25. o->moveToThread(&thread);
    26. }
    To copy to clipboard, switch view to plain text mode 
    (Note: this code is incomplete, I have not tested it, not even tried to compile it. This is only to give a simple idea of what I would try. Note that I did not put anything to stop the endless calls to o->method() and push o back to the main thread. That requires a little more code.)

  6. The following user says thank you to yeye_olive for this useful post:

    Ocsidot (10th August 2012)

  7. #6
    Join Date
    Jul 2012
    Posts
    123
    Thanks
    4
    Thanked 2 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Trouble while destroying thread

    I have small question what moveToThread do? and is some way how working with QWidget in my thread ?

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

    Default Re: Trouble while destroying thread

    move to thread essentially just changes a thread ID (i believe). Events and queued slot connections only get handled in the thread that they belong to. This is taken care of by the event loop in that thread (if it exists).

    Since widget events can only be handled in the main thread, you will not have any success moving QWidgets to different threads, only QObjects are suitable.

    Something that is a bit confusing:
    Qt Code:
    1. void xxx::some_func_in_maina_thread()
    2. {
    3.  
    4. QThread* thrd = new QThread;
    5.  
    6. QObject* obj = new QObject;
    7.  
    8.  
    9. // thrd and obj are in main thread. thrd *represents* the thread, but thrd is actually a QObject in the main thread
    10.  
    11. obj->moveToThread(thrd); // changes the thread id of `obj` to the thread id of the thread that `thrd` represents
    12. }
    To copy to clipboard, switch view to plain text mode 
    Last edited by amleto; 9th August 2012 at 20:29.
    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.

  9. #8
    Join Date
    Aug 2012
    Posts
    3
    Thanks
    1
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Trouble while destroying thread

    Thanks to all of tou, I've find a solution. As Yeye_olive suggested, I've done this:

    Qt Code:
    1. #ifndef _THREADWORKER_H_
    2. #define _THREADWORKER_H_
    3.  
    4. #include "QtCore/qobject.h"
    5. #include "QtCore/qthread.h"
    6. #include "QtCore/qtimer.h"
    7.  
    8. class ThreadWorker : public QObject
    9. {
    10. Q_OBJECT
    11.  
    12. private:
    13. int _frequency;
    14. QTimer _timer;
    15. QThread _thread;
    16.  
    17. public:
    18. ThreadWorker(int frequency = 300);
    19. ~ThreadWorker();
    20.  
    21. /*!
    22. \brief Create a worker which call the specified slot in th specified thread
    23. \param thread The thread to use
    24. \param source The object which contains the slot to use
    25. \param slot The slot to use
    26. */
    27. void createWorker(const QObject* source, const char *slot);
    28.  
    29. /*!
    30. \brief Defines what to do when the thread ends
    31. \param source The object which contains the slot to use
    32. \param slot The slot to use
    33. */
    34. void onWorkerEnded(const QObject* source, const char *slot);
    35.  
    36. /*!
    37. \brief Sets the call frequency for the threaded method
    38. \param frequency Frequency in millsecond (default value: 300ms)
    39. */
    40. void setFrequency(int frequency);
    41.  
    42. /*!
    43. \brief Starts the thread worker
    44. */
    45. void start();
    46.  
    47. /*!
    48. \brief Gets the state of the worker
    49. */
    50. bool isRunning() { return _thread.isRunning(); }
    51.  
    52. private slots:
    53. void stop();
    54.  
    55. public slots:
    56. /*!
    57. \brief a slot to indicates the end of our current work
    58. */
    59. void terminate();
    60.  
    61. signals:
    62. void finished();
    63. };
    64.  
    65. #endif
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. #include "ThreadWorker.h"
    2.  
    3. ThreadWorker::ThreadWorker(int frequency)
    4. {
    5. _frequency = frequency;
    6. _timer.setInterval(_frequency);
    7.  
    8. connect(&_thread, SIGNAL(started()), &_timer, SLOT(start()));
    9. connect(this, SIGNAL(finished()), &_thread, SLOT(quit()));
    10. connect(this, SIGNAL(finished()), this, SLOT(stop()));
    11.  
    12. _timer.moveToThread(&_thread);
    13. }
    14.  
    15. ThreadWorker::~ThreadWorker()
    16. {
    17. stop();
    18. _thread.quit();
    19. _thread.wait();
    20. }
    21.  
    22. void ThreadWorker::createWorker(const QObject* source, const char *slot)
    23. {
    24. connect(&_timer, SIGNAL(timeout()), source, slot, Qt::DirectConnection);
    25. }
    26.  
    27. void ThreadWorker::onWorkerEnded(const QObject* source, const char *slot)
    28. {
    29. connect(&_thread, SIGNAL(finished()), source, slot, Qt::DirectConnection);
    30. }
    31.  
    32. void ThreadWorker::setFrequency(int frequency)
    33. {
    34. _frequency = frequency;
    35. }
    36.  
    37. void ThreadWorker::start()
    38. {
    39. if(!_thread.isRunning())
    40. _thread.start();
    41. }
    42.  
    43. void ThreadWorker::stop()
    44. {
    45. if(_timer.isActive())
    46. {
    47. _timer.stop();
    48. }
    49. }
    50.  
    51. void ThreadWorker::terminate()
    52. {
    53. if(_timer.isActive())
    54. {
    55. emit finished();
    56. }
    57. }
    To copy to clipboard, switch view to plain text mode 

    Again, thank you very much for your help

  10. #9
    Join Date
    Oct 2009
    Posts
    483
    Thanked 97 Times in 94 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Trouble while destroying thread

    Here are a few comments:

    1. In createWorker(), you make a direct connection between timer and source which live in distinct threads. Qt explicitly forbids that. You should move source to _thread instead (see Manager::add() in my code).

    2. In onWorkerEnded(), you make a direct connection again, which is only allowed if source lives in the same thread as the _thread object itself, i.e. presumably the main thread, NOT the one managed by _thread. More generally, I have yet to find a use case for forcing a direct connection: the default behaviour (auto connection) behaves like a direct connection if it is allowed and like a queued connection otherwise.
    By the way, why do you even need onWorkerEnded()?

    3. In ThreadWorker::stop(), you call _timer.stop() but _timer lives in another thread and QTimer's documentation explicitly states that a QTimer must be started/stopped from the thread in which it lives. That is why in my code I start the timer with
    QObject::connect(&thread, SIGNAL(started()), &timer, SLOT(start()));
    instead of
    timer.start();
    In the same fashion you should stop the timer this way:
    QMetaObject::invokeMethod(&_timer, "stop");
    4. It seems that you do not really need the ThreadWorker::finished() signal and the ThreadWorker::stop() slot. You could simply replace the body of ThreadWorker::terminate() with
    QMetaObject::invokeMethod(&_timer, "stop");
    _thread.quit();
    but I do not know if QTimer::stop() will always be executed before _thread's event loop terminates (IMHO the documentation is a bit lacking wrt this very specific point). If I wanted to ensure that, I would invoke a slot for a custom QObject living in the worker thread that would stop the timer (direct method call), then make the event loop exit (not a direct call).

    I understand this whole business can be really confusing. I strongly recommend that you read the documentation on signals and slots across threads, QThread, and QTimer.

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

    Default Re: Trouble while destroying thread

    ocsidot, unless you are experienced Qt programmer there is just no need to be be using Qt::DirectConnection explicitly.

    So my advice is to just stop it!
    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.

Similar Threads

  1. Replies: 1
    Last Post: 28th March 2012, 18:58
  2. Replies: 9
    Last Post: 28th November 2009, 20:31
  3. destroying object...
    By mind_freak in forum General Programming
    Replies: 3
    Last Post: 22nd July 2009, 18:49
  4. Destroying a QList the right way
    By Cruz in forum Newbie
    Replies: 1
    Last Post: 19th January 2009, 10:52
  5. Window not closing or destroying
    By spraff in forum Qt Programming
    Replies: 5
    Last Post: 13th December 2008, 15:10

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.