Results 1 to 7 of 7

Thread: Cross thread signals (QueuedConnection). Miss SOME signals!

  1. #1

    Default Cross thread signals (QueuedConnection). Miss SOME signals!

    Hi all.

    I have weired problem with signals sending between threads.

    1) I have a thread. In the run() function I create a signals reciever object and connect signals to it:
    Qt Code:
    1. void LogServiceThread::run()
    2. {
    3. // Create worker.
    4. try
    5. {
    6. m_impl->m_worker.reset(new LogWorker(m_impl->m_fileName));
    7. }
    8. catch (...)
    9. {
    10. // Ignore all exceptions. If something gone wrong with worker - continue work silently.
    11. }
    12. // Connect signals to worker.
    13. if (!m_impl->m_worker.isNull())
    14. {
    15. connect(this, SIGNAL(writeAsynchSignal(QString)), m_impl->m_worker.data(), SLOT(writeMessage(QString)), Qt::QueuedConnection);
    16. }
    17. // Run event loop.
    18. exec();
    19. }
    To copy to clipboard, switch view to plain text mode 
    2) Now I try to send som signals to it by main thread
    Qt Code:
    1. void LogServiceThread::writeAsynch(const QString & string)
    2. {
    3. emit writeAsynchSignal(string);
    4. }
    To copy to clipboard, switch view to plain text mode 

    So basically, this is an asynchronous thread safe logger. And I got weired problem: sometimes SOME log messages are missing. Some signals are emited but never come to slot! Sometimes I got all messages during run, some times only few.

    What I am missing?

    Thanks.

  2. #2
    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: Cross thread signals (QueuedConnection). Miss SOME signals!

    What happens if you change the signature of writeAsynch() to:
    Qt Code:
    1. void writeAsynch(QString string)
    To copy to clipboard, switch view to plain text mode 
    ==========================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.

  3. #3
    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: Cross thread signals (QueuedConnection). Miss SOME signals!

    @up: this doesn't change anything.

    @topic: not enough information! I have no idea what you should say more! First check debug logs, maybe Qt warns about some run time problems.
    Secondly describe what you are trying to do? Maybe you can do it better way?

  4. #4

    Default Re: Cross thread signals (QueuedConnection). Miss SOME signals!

    Quote Originally Posted by MarekR22 View Post
    @topic: not enough information! I have no idea what you should say more! First check debug logs, maybe Qt warns about some run time problems.
    Secondly describe what you are trying to do? Maybe you can do it better way?
    Ok, basically this is simple thing.
    I have a LogServiceThread object, which acts like a thread-safe object for logging. During the run() function I create a ThreadWorker object. It leaves in this thread and it responsible for actual writing of the log messages to the file. So, I service the log writing in separate thread. If other threads want to send something to log - they send a message to ThreadWorker using LogServiceThread::writeAsynch or (writeSynch if needed). writeAsynch returns immediately while message is added to the event queue of the log servicing thread. writeSynch is also executed in the same thread, but function is not returning until the message is really written to file (this is usefuly for example when logging qFatal, because after it the process is terminated).

    Here is full implementation of these classes.
    Qt Code:
    1. ////////////////////////////////////////////////////////////////////////
    2. /// LogServiceThreadImpl implementation.
    3. ////////////////////////////////////////////////////////////////////////
    4. struct LogServiceThread::LogServiceThreadImpl
    5. {
    6. QString m_fileName;
    7. };
    8.  
    9. ////////////////////////////////////////////////////////////////////////
    10. /// LogServiceThread implementation.
    11. ////////////////////////////////////////////////////////////////////////
    12. LogServiceThread::LogServiceThread(const QString & fileName, QObject * parent)
    13. : QThread(parent), m_impl(new LogServiceThreadImpl)
    14. {
    15. m_impl->m_fileName = fileName;
    16. }
    17.  
    18. LogServiceThread::~LogServiceThread()
    19. {
    20.  
    21. }
    22.  
    23. void LogServiceThread::run()
    24. {
    25. QScopedPointer<LogWorker> worker;
    26. // Create worker.
    27. try
    28. {
    29. worker.reset(new LogWorker(m_impl->m_fileName));
    30. }
    31. catch (...)
    32. {
    33. // Ignore all exceptions. If something gone wrong with worker - continue work silently.
    34. // We dont wont application to crash, cause of log.
    35. }
    36. // Connect signals to worker.
    37. if (!worker.isNull())
    38. {
    39. connect(this, SIGNAL(writeAsynchSignal(QString)), worker.data(), SLOT(writeMessage(QString)), Qt::QueuedConnection);
    40. connect(this, SIGNAL(writeSynchSignal(QString)), worker.data(), SLOT(writeMessage(QString)), Qt::BlockingQueuedConnection);
    41. }
    42. // Run event loop.
    43. exec();
    44. }
    45.  
    46. void LogServiceThread::writeAsynch(const QString & string)
    47. {
    48. emit writeAsynchSignal(string);
    49. }
    50.  
    51. void LogServiceThread::writeSynch(const QString & string)
    52. {
    53. emit writeSynchSignal(string);
    54. }
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. ////////////////////////////////////////////////////////////////////////
    2. /// LogWorkerImpl implementation
    3. ////////////////////////////////////////////////////////////////////////
    4. struct LogWorker::LogWorkerImpl
    5. {
    6. QScopedPointer<QFile> m_file;
    7. QScopedPointer<QTextStream> m_stream;
    8. };
    9.  
    10. ////////////////////////////////////////////////////////////////////////
    11. /// LogWorker implementation
    12. ////////////////////////////////////////////////////////////////////////
    13. LogWorker::LogWorker(const QString & fileName, QObject * parent)
    14. : QObject(parent), m_impl(new LogWorkerImpl)
    15. {
    16. // Create file object (temporary for now)
    17. QScopedPointer<QFile> file(new QFile(fileName));
    18. if (file->open(QIODevice::WriteOnly | QIODevice::Text))
    19. {
    20. // Create text stream
    21. QScopedPointer<QTextStream> stream(new QTextStream(file.data()));
    22. // Now we succeeded:
    23. m_impl->m_file.reset(file.take());
    24. m_impl->m_stream.reset(stream.take());
    25. }
    26. }
    27.  
    28. LogWorker::~LogWorker()
    29. {
    30. // FIrst delete stream.
    31. m_impl->m_stream.reset(0);
    32. // Than file.
    33. m_impl->m_file.reset(0);
    34. }
    35.  
    36. void LogWorker::writeMessage(QString s)
    37. {
    38. (*m_impl->m_stream.data()) << s << endl;
    39. m_impl->m_file->flush();
    40. }
    To copy to clipboard, switch view to plain text mode 

    So this is quite simple.

    The Qt doesn't send any debug messages. Btw, all qt messages are redirected to that log. You could say that I miss some qt messages during construction of the LogServiceThread. But no: 1) I checked that. 2) I firstly create LogServiceThread and only than install message handler (so before this - qt messages are sent to standard output, and there is nothing there).


    Added after 15 minutes:


    Ok, I have found a reason. Although this seems strange to me anyway.
    If I put some long dummy operation (2 seconds to perform) after LogServiceThread construction and before first log message sent - I get it working.
    Something like this: for (int i = 0; i < 100000000; i++) cos(0.54f);
    This brings me to the point: if I send message before the QThread::exec() is called (event loop is runned) - the signals are missing! Ok, although this seems not good - it can be expected.
    But there is something I could considered as a bug of Qt. If the above scenario occurs - the messages that are sent after the starting of even loop also CAN miss! Because I have few messages written on application close, and I still miss them. I close application after few seconds of running it - so there is a guarantee that exec() already called.

    So, although this looks like a Qt bug for me, I will add a synchronization point to ensure that no signals emitted until exec() is called. This should work.


    Added after 9 minutes:


    Another question.
    How can I know that event loop was already created and I can send signals? I could set some flag just before calling exec(), but this is also not safe, cause who knows what is inside exec() and when I really can already send signals?


    Added after 11 minutes:


    Wow, I'm so silly!
    Nothing about Qt event queue or something.

    1) The messages on startup are missing because they are sent before LogWorker is created!
    2) The messages on shutdown are missing because quit() event comes out of order (which is ok, this is another problem to think on).

    Resolved!
    Last edited by progDes; 29th April 2011 at 13:20.

  5. #5
    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: Cross thread signals (QueuedConnection). Miss SOME signals!

    @up: this doesn't change anything.
    The idea was that since its a reference, the referenced object might have changed to be a null string before the thread came to process the slot.
    ==========================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. #6

    Default Re: Cross thread signals (QueuedConnection). Miss SOME signals!

    Quote Originally Posted by high_flyer View Post
    The idea was that since its a reference, the referenced object might have changed to be a null string before the thread came to process the slot.
    No. Look at the signal and slot definition, the string is passed by value.

  7. #7
    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: Cross thread signals (QueuedConnection). Miss SOME signals!

    Quote Originally Posted by high_flyer View Post
    The idea was that since its a reference, the referenced object might have changed to be a null string before the thread came to process the slot.
    Read qt documentation about passing signal to slots. Const reference and value doesn't have any differences, copy is always made (in case of QString shallow copy).

    @topic:
    if you mixed calls of LogServiceThread::writeAsynch and LogServiceThread::writeSynch even in single thread then you did a big mistake.
    In one case you enforced call of LogWorker::writeMessage from LogServiceThread in another case it happens from custom (probably mian) thread.
    But you method LogWorker::writeMessage is not thread safe, so you are corrupting data in stream in unpredictable way.
    Use only writeAsynch method this will be thread safe!

    In general qt delivers a loger. Just include QDebug header file and use it:
    Qt Code:
    1. qDebug() << "Messege" << value << value;
    To copy to clipboard, switch view to plain text mode 
    It is possible to store qDebug in a file, I have to find it in documentation (it is possible that invoking application with "-o filename" option is enough I'm not sure)

Similar Threads

  1. Replies: 5
    Last Post: 22nd February 2011, 21:21
  2. Replies: 1
    Last Post: 24th October 2010, 11:09
  3. Replies: 8
    Last Post: 1st June 2009, 19:59
  4. Problem using signals and thread
    By aarelovich in forum Qt Programming
    Replies: 2
    Last Post: 30th June 2008, 13:57
  5. QThread and signals (linux/UNIX signals not Qt Signals)
    By Micawber in forum Qt Programming
    Replies: 1
    Last Post: 28th November 2007, 22:18

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.