Results 1 to 15 of 15

Thread: QueuedConnection's and threads

  1. #1
    Join Date
    Jan 2007
    Location
    Augsburg, Germany
    Posts
    75
    Thanks
    4
    Thanked 6 Times in 5 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default QueuedConnection's and threads

    Hello there!

    In my code I'm using non-threadsafe classes from our company. For that I've splitted my application into two threads. The main thread runs the GUI, the other one the complete non-threadsafe process. Both communicate only via QueuedConnection's. The non-gui thread has a private class (created in thread::run()) which does all the work for it and notifies the thread object about everything that happens. To forward these notifies, the private and the working-thread class have the same signals and slots. These are simply connected to each other which may cause my problem: Deadlock

    Qt Code:
    1. void thread::run()
    2. {
    3. // Delete the old object on restart
    4. if ( m_private )
    5. delete m_private;
    6.  
    7. // Create our private object
    8. m_private = new thread_private;
    9.  
    10. // And connect its signals to ours
    11. connect( m_private, SIGNAL(databaseOpened(bool)), this, SIGNAL(databaseOpened(bool)) );
    12. connect( m_private, SIGNAL(databaseOpening()) , this, SIGNAL(databaseOpening()) );
    13. }
    To copy to clipboard, switch view to plain text mode 

    The main window is connected on databaseOpened() etc. on the thread object.

    Everything works except in one case: I'm starting a search from the database and get 200 results returned. For each result an event is fired (private (queued)-> thread (direct)-> mainwindow). There happens the deadlock and I can't explain why

  2. #2
    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: QueuedConnection's and threads

    What kind of class is "thread_private"? Are you not running an event loop?
    J-P Nurmi

  3. #3
    Join Date
    Jan 2007
    Location
    Augsburg, Germany
    Posts
    75
    Thanks
    4
    Thanked 6 Times in 5 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: QueuedConnection's and threads

    Quote Originally Posted by jpn View Post
    What kind of class is "thread_private"? Are you not running an event loop?
    thread_private is derived from QObject. The thread::run() function starts its own event loop with QThread::exec(). The working thread deadlocks in QCoreApplication:ostEvent() while the other one (main) hangs in QWaitConditionPrivate::wait() coming from some scary stack (__fstat()) - maybe cause the debugger telled that it can not pause while deadlocking.

  4. #4
    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: QueuedConnection's and threads

    Quote Originally Posted by gri View Post
    The thread::run() function starts its own event loop with QThread::exec().
    Hmm, where is it actually called because I don't see it there?
    J-P Nurmi

  5. #5
    Join Date
    Jan 2007
    Location
    Augsburg, Germany
    Posts
    75
    Thanks
    4
    Thanked 6 Times in 5 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: QueuedConnection's and threads

    Quote Originally Posted by jpn View Post
    Hmm, where is it actually called because I don't see it there?
    I've just shortened down the code for the post. Actually there are more signals. The one causing the deadlock works with own created types which are registered via Q_DECLARE_METATYPE() and qRegisterMetaType<x>().

    Qt Code:
    1. void thread::safeStart()
    2. {
    3. // Invoke the "thread" method only
    4. this->run();
    5. }
    6.  
    7. void thread::run()
    8. {
    9. // Delete the old object on restart
    10. if ( m_private )
    11. delete m_private;
    12.  
    13. // Create our private object
    14. m_private = new thread_private;
    15.  
    16. // And connect its signals to ours
    17. connect( m_private, SIGNAL(databaseOpened(bool)), this, SIGNAL(databaseOpened(bool)) );
    18. connect( m_private, SIGNAL(databaseOpening()) , this, SIGNAL(databaseOpening()) );
    19. connect( m_private, SIGNAL(databaseClosed()) , this, SIGNAL(databaseClosed()) );
    20.  
    21. connect( m_private, SIGNAL(searchPreparing()) , this, SIGNAL(searchPreparing()) );
    22. connect( m_private, SIGNAL(searchPrepared()) , this, SIGNAL(searchPrepared()) );
    23. connect( m_private, SIGNAL(searchStarted()) , this, SIGNAL(searchStarted()) );
    24. connect( m_private, SIGNAL(searchProgress(double)) , this, SIGNAL(searchProgress(double)) );
    25. connect( m_private, SIGNAL(searchResultsCount(int)), this, SIGNAL(searchResultsCount(int)) );
    26. connect( m_private, SIGNAL(searchResultEntry(const SearchNode&,const QList<SearchAlgo>&,int,double)),
    27. this, SIGNAL(searchResultEntry(const SearchNode&,const QList<SearchAlgo>&,int,double)) );
    28. connect( m_private, SIGNAL(searchFinished()) , this, SIGNAL(searchFinished()) );
    29.  
    30. connect( m_private, SIGNAL(errorHappened(const QString&)), this, SIGNAL(errorHappened(const QString&)) );
    31.  
    32. // Start the event loop if we are our own thread
    33. if ( this->isRunning() )
    34. {
    35. // Start the event loop
    36. this->exec();
    37. }
    38. else // Fake the start (in safe mode without threading)
    39. emit started();
    40. }
    To copy to clipboard, switch view to plain text mode 
    Last edited by jacek; 23rd January 2007 at 22:21. Reason: wrapped too long line

  6. #6
    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: QueuedConnection's and threads

    Quote Originally Posted by gri View Post
    Qt Code:
    1. void thread::safeStart()
    2. {
    3. // Invoke the "thread" method only
    4. this->run();
    5. }
    To copy to clipboard, switch view to plain text mode 
    Hmm, where does this thread::safeStart() get called from? You must start the thread by calling QThread::start(), not by QThread::run(). QThread::start() does the work under hood and actually starts a new thread and calls QThread::run() in the newly created thread. QThread::start() is safe to call many times, it does nothing if the thread is already running. You should never invoke QThread::run() by yourself..
    J-P Nurmi

  7. #7
    Join Date
    Jan 2007
    Location
    Augsburg, Germany
    Posts
    75
    Thanks
    4
    Thanked 6 Times in 5 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: QueuedConnection's and threads

    Quote Originally Posted by jpn View Post
    Hmm, where does this thread::safeStart() get called from? You must start the thread by calling QThread::start(), not by QThread::run(). QThread::start() does the work under hood and actually starts a new thread and calls QThread::run() in the newly created thread. QThread::start() is safe to call many times, it does nothing if the thread is already running.
    This function is not called. It's only for a safe mode because some other people here fear that threading could crash the program ... the thread is started with QThread::start(). With the "safe" method no deadlock occurs ..

  8. #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: QueuedConnection's and threads

    "thread_private* m_private" could be allocated on the stack. QThread::exec() blocks anyway. Maybe that's causing the problem if the thread is started/stopped multiple times and the thread_private has been allocated in the "previous" thread?
    J-P Nurmi

  9. #9
    Join Date
    Jan 2007
    Location
    Augsburg, Germany
    Posts
    75
    Thanks
    4
    Thanked 6 Times in 5 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: QueuedConnection's and threads

    Quote Originally Posted by jpn View Post
    "thread_private* m_private" could be allocated on the stack. QThread::exec() blocks anyway. Maybe that's causing the problem if the thread is started/stopped multiple times and the thread_private has been allocated in the "previous" thread?
    Also not that The thread is only started once in the constructor of the main window and quit()'s and wait()'s until termination in its destructor. All signals except of searchResultEntry() work. The deadlock happens while the private object (running in working thread) sends a event to the thread object (running in main thread).

    When setting a breakpoint in the receiving slot no deadlock occurs. So it seems to be that there are too much events fired I think.
    Last edited by gri; 23rd January 2007 at 15:09. Reason: updated contents

  10. #10
    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: QueuedConnection's and threads

    Have you tried checking QThread::currentThread() in relevant slots to assure they actually are executed in the expected thread context?
    J-P Nurmi

  11. #11
    Join Date
    Jan 2007
    Location
    Augsburg, Germany
    Posts
    75
    Thanks
    4
    Thanked 6 Times in 5 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: QueuedConnection's and threads

    Quote Originally Posted by jpn View Post
    Have you tried checking QThread::currentThread() in relevant slots to assure they actually are executed in the expected thread context?
    The slot is invoked Queued (coming from QEventLoop:rocessEvents()). QThread::currentThread() returns the main/GUI thread which is the one, where it should be.

    Maybe it's the use of custom objects via const reference (usally gets copied), I'll try to use pointers and see, what happens.

  12. #12
    Join Date
    Jan 2007
    Location
    Augsburg, Germany
    Posts
    75
    Thanks
    4
    Thanked 6 Times in 5 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: QueuedConnection's and threads

    Ok, error found.

    If I send my own class via QueuedConnection the event loop deadlocks after 2 - 3 calls. Without my own class (using Qt classes like QString etc.) the same call works!

    So what am I doing wrong? Code of custom node:

    Qt Code:
    1. class SearchNode : public QObject
    2. {
    3. Q_OBJECT
    4.  
    5. public:
    6. SearchNode(QObject* parent = 0);
    7. SearchNode(const QString& name, const QString& relativePath, QObject* parent = 0);
    8. SearchNode(const SearchNode& cpy);
    9. ~SearchNode();
    10.  
    11. SearchNode& operator=(const SearchNode& cpy);
    12.  
    13. QString relativePath() const;
    14. void setRelativePath(const QString& d);
    15.  
    16. QString name() const;
    17. void setName(const QString& d);
    18.  
    19. protected:
    20. QString m_relativePath;
    21. QString m_name;
    22. };
    23.  
    24. Q_DECLARE_METATYPE(SearchNode);
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. int main(int argc, char* argv[])
    2. {
    3. qRegisterMetaType<SearchNode>();
    4. ...
    5. }
    To copy to clipboard, switch view to plain text mode 
    Last edited by gri; 23rd January 2007 at 17:08. Reason: updated contents

  13. #13
    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: QueuedConnection's and threads

    Oh, SearchNode is a QObject. That must be causing the problem. How did you implement the copy constructor? QObject's cannot be copied.

    EDIT: Do the SearchNodes have some hierarchy or what's the reason for choosing QObject? Try looking for some alternative way of constructing the hierarchy for example by simply using Qt's containers.
    J-P Nurmi

  14. The following user says thank you to jpn for this useful post:

    gri (23rd January 2007)

  15. #14
    Join Date
    Jan 2007
    Location
    Augsburg, Germany
    Posts
    75
    Thanks
    4
    Thanked 6 Times in 5 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: QueuedConnection's and threads

    Quote Originally Posted by jpn View Post
    Oh, SearchNode is a QObject. That must be causing the problem. How did you implement the copy constructor? QObject's cannot be copied.
    Ohhh, you're right I think. Did'nt knew that QObject can not be copied. Altough here is my copy constructor which does not copy anything of QObject.

    Qt Code:
    1. SearchNode::SearchNode(const SearchNode& cpy)
    2. {
    3. *this = cpy;
    4. }
    5.  
    6. SearchNode& SearchNode::operator=(const SearchNode& cpy)
    7. {
    8. this->m_relativePath = cpy.m_relativePath;
    9. this->m_name = cpy.m_name;
    10.  
    11. return *this;
    12. }
    To copy to clipboard, switch view to plain text mode 

  16. #15
    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: QueuedConnection's and threads

    Quote Originally Posted by gri View Post
    Altough here is my copy constructor which does not copy anything of QObject.

    Qt Code:
    1. SearchNode::SearchNode(const SearchNode& cpy)
    2. {
    3. *this = cpy;
    4. }
    To copy to clipboard, switch view to plain text mode 
    Of course it does - QObject has some internal data which can't be shared. And by the way, there is no point implementing such a copy constructor - the compiler would generate such itself. You should only implement a copy constructor if you need something different then simple substitution of all members of one objects with values from the other object.

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.