Results 1 to 14 of 14

Thread: Problem receiving signals between QNetworkReply, QTimer::singleShot and qeventloop

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Join Date
    Mar 2016
    Posts
    7
    Qt products
    Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Symbian S60 Maemo/MeeGo

    Default Problem receiving signals between QNetworkReply, QTimer::singleShot and qeventloop

    I'm having rather peculiar problem with my Qt application. The application communicates with another application through REST API. Calls are made by functions that will either return the response or empty value if timeout happens.
    Code
    Qt Code:
    1. QNetworkReply* reply = nam_.post(request, jsonBytes);
    2. connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
    3. QTimer::singleShot(TIMEOUT, &loop, SLOT(quit())); //timeout
    4. QTimer::singleShot(TIMEOUT, this, SLOT(sayHello())); //timeout
    5.  
    6. DBG << "pv Loop begin";
    7. loop.exec();
    8. DBG << "pv Loop end";
    9. QByteArray response = reply->readAll();
    10. return bytesToVariantMap(response);
    To copy to clipboard, switch view to plain text mode 
    In single try this works. However when multiple threads are running and calls are made in rapid succession problems occur: loop.exec() never exits and sayHello() is never executed. It seems as if the whole event system becomes unpredictable. Oddly enough adding delay before loop.exec seems to reduce the problem.
    Qt Code:
    1. QThread::msleep(300); //Without this delay, loop.exec might deadlock (WTF...)
    2. loop.exec();
    To copy to clipboard, switch view to plain text mode 

    I tried this in both Qt 5.4 and 5.5

  2. #2
    Join Date
    Dec 2009
    Location
    New Orleans, Louisiana
    Posts
    791
    Thanks
    13
    Thanked 153 Times in 150 Posts
    Qt products
    Qt5
    Platforms
    MacOS X

    Default Re: Problem receiving signals between QNetworkReply, QTimer::singleShot and qeventloo

    In my opinion, you should abandon trying to force a synchronous result (using QEventLoop) for the QNetwork* functions, which are all asynchronous. Use the QNetworkReply::finished() signal instead to QNetworkReply::readAll() the result.

    If you need to abort requests that exceed some timeout, you can use QTimer and when the timer pops, use QNetworkReply::abort() or stop the timer if you receive the finished signal first, etc.
    I write the best type of code possible, code that I want to write, not code that someone tells me to write!

  3. #3
    Join Date
    Mar 2016
    Posts
    7
    Qt products
    Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Symbian S60 Maemo/MeeGo

    Default Re: Problem receiving signals between QNetworkReply, QTimer::singleShot and qeventloo

    Update to the problem. I isolated the problem so that only qeventloop and singleshots are used. It seems to work flawlessly.

    Qt Code:
    1. QTimer::singleShot(TIMEOUT, &loop, SLOT(quit())); //timeout
    2. QTimer::singleShot(TIMEOUT, this, SLOT(sayHello())); //timeout
    3. DBG << "pv Loop begin";
    4. loop.exec();
    5. DBG << "pv Loop end";
    To copy to clipboard, switch view to plain text mode 


    Added after 5 minutes:


    Quote Originally Posted by jefftee View Post
    you should abandon trying to force a synchronous result
    There are numerous reasons why I chose this approach. Main reason being that synchronous calls are a lot cleaner and resemble local calls which makes the code more approachable. Synchronous calls are not the core problem and hope this conversation does not derail into sync vs async.
    Last edited by Desujoi; 7th March 2016 at 09:56.

  4. #4
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Problem receiving signals between QNetworkReply, QTimer::singleShot and qeventloo

    This isn't sync vs async since this is async.

    It is of course your choice to do it this way, but make sure you are aware of the consequences.
    - Nested event loops can lead to situations that are similar to re-entrancy, e.g. a method that "blocks" being called again.
    - You need to either make sure that the object cannot be deleted while it is executing the nested event loop or you cannot rely on it existing after the event loop exits

    The two most common patterns to avoid these problems are
    - truely blocking
    - encapsulating the async work in a "job" object and only handle its final result asynchronously

    Cheers,
    _

  5. #5
    Join Date
    Mar 2016
    Posts
    7
    Qt products
    Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Symbian S60 Maemo/MeeGo

    Default Re: Problem receiving signals between QNetworkReply, QTimer::singleShot and qeventloo

    I have discovered that qeventloop is not independent from the maineventloop as is discussed in this forum post: http://stackoverflow.com/questions/2...s-manually-res
    It seems that creating new qeventloop can in fact block maineventloop from running. AFAIK this means signals and slots will cease to work.

  6. #6
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Problem receiving signals between QNetworkReply, QTimer::singleShot and qeventloo

    Quote Originally Posted by Desujoi View Post
    It seems that creating new qeventloop can in fact block maineventloop from running. AFAIK this means signals and slots will cease to work.
    No.
    Hence the aforementions consequences of using nested event loops.
    Which is also what the stackoverflow post describes.

    Also signal/slots within a single thread don't depend on events.

    Cheers,
    _

  7. #7
    Join Date
    Mar 2016
    Posts
    7
    Qt products
    Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Symbian S60 Maemo/MeeGo

    Default Re: Problem receiving signals between QNetworkReply, QTimer::singleShot and qeventloo

    Okay, so I ended up moving the class to another thread in its constructor.
    Qt Code:
    1. moveToThread(&thread_);
    2. thread_.start(QThread::HighestPriority);
    To copy to clipboard, switch view to plain text mode 
    Now "sayHello" slot started responding. However, qeventloop still does not quit on timeout. I tried to make qeventloop member variable and then called its quit method in sayHello(). Nothing happened, the program still locks in loop.exec(). I can't wrap my head around this.
    Last edited by Desujoi; 7th March 2016 at 18:02.

  8. #8
    Join Date
    Dec 2009
    Location
    New Orleans, Louisiana
    Posts
    791
    Thanks
    13
    Thanked 153 Times in 150 Posts
    Qt products
    Qt5
    Platforms
    MacOS X

    Default Re: Problem receiving signals between QNetworkReply, QTimer::singleShot and qeventloo

    Quote Originally Posted by Desujoi View Post
    Synchronous calls are not the core problem and hope this conversation does not derail into sync vs async.
    That certainly wasn't my intent at all, I simply stated my opinion, not fact. It's your code, you can do whatever you want, but as @anda_skoa pointed out, using QEventLoop has its drawbacks and pitfalls.

    Edit: And to be clear for future readers, using QEventLoop doesn't change the behavior of the QNetwork* async calls, it simply is a kludge many have used (me included) to block while waiting for asynchronous calls to complete.
    I write the best type of code possible, code that I want to write, not code that someone tells me to write!

  9. #9
    Join Date
    Mar 2016
    Posts
    7
    Qt products
    Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Symbian S60 Maemo/MeeGo

    Default Re: Problem receiving signals between QNetworkReply, QTimer::singleShot and qeventloo

    I think I figured it out!
    a) QEventLoop::exec() does not only wait. It let's the same thread perform signal-slot-handling anywhere else in the code.
    b) In my case execution was changed to a slot triggered by QTimer.
    c) This slot halted in Mutex lock.
    d) Hence whole qevenloop got frozen.
    Feel free to correct me if I'm wrong. This was definitely a little confusing .
    In essence: QTimer executes slot ->passes mutex -> qeventloop called -> execution moved back to the slot by qtimer -> mutex unpassable.
    Last edited by Desujoi; 7th March 2016 at 22:47.

  10. #10
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Problem receiving signals between QNetworkReply, QTimer::singleShot and qeventloo

    Quote Originally Posted by Desujoi View Post
    I think I figured it out!
    a) QEventLoop::exec() does not only wait. It let's the same thread perform signal-slot-handling anywhere else in the code.
    No, the event loop is not involved with signal-slot-handling.

    Quote Originally Posted by Desujoi View Post
    c) This slot halted in Mutex lock.
    d) Hence whole qevenloop got frozen.
    That's the very job of a mutex.
    Only one thread can have the mutex locked at any given time.
    It would be useless if it didn't block any further attempt at locking.


    Quote Originally Posted by Desujoi View Post
    In essence: QTimer executes slot ->passes mutex -> qeventloop called -> execution moved back to the slot by qtimer -> mutex unpassable.
    Why on earth do you use a mutex in a single threaded application?

    Cheers,
    _

  11. #11
    Join Date
    Mar 2016
    Posts
    7
    Qt products
    Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Symbian S60 Maemo/MeeGo

    Default Re: Problem receiving signals between QNetworkReply, QTimer::singleShot and qeventloo

    Quote Originally Posted by anda_skoa View Post
    Why on earth do you use a mutex in a single threaded application?
    _
    The answer is pretty simple: I thought it was not single threaded. My idea at the time was that QTimer spawned a new thread for every slot call. It is not at all obvious.
    Last edited by Desujoi; 7th March 2016 at 23:43.

  12. #12
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Problem receiving signals between QNetworkReply, QTimer::singleShot and qeventloo

    Quote Originally Posted by Desujoi View Post
    The answer is pretty simple: I thought it was not single threaded. My idea at the time was that QTimer spawned a new thread for every slot call. It is not at all obvious.
    I don't see anything in the QTimer documentation that would suggest it is using a thread.

    That would be pretty horrible, it would make even otherwise simple programs hard to get right, safe multithreading is not trivial.

    Cheers,
    _

  13. #13
    Join Date
    Mar 2016
    Posts
    7
    Qt products
    Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Symbian S60 Maemo/MeeGo

    Default Re: Problem receiving signals between QNetworkReply, QTimer::singleShot and qeventloo

    I ended up using QtConcurrent::run and creating thread specific QNetworkAccessManager when needed. This solves the dead lock of multiple slots waiting for the same response. This is temporary solution and I might end up separating nam calls into separate thread and then use thread join to wait.

  14. #14
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Problem receiving signals between QNetworkReply, QTimer::singleShot and qeventloo

    Quote Originally Posted by Desujoi View Post
    I might end up separating nam calls into separate thread and then use thread join to wait.
    A.k.a "true blocking" as outlined as one of the possible solutions in comment #4

    Cheers,
    _

Similar Threads

  1. QTimer::singleShot(0, ... confusion
    By bjoern83 in forum Qt Programming
    Replies: 5
    Last Post: 9th October 2022, 10:30
  2. Replies: 3
    Last Post: 31st January 2010, 16:56
  3. Replies: 8
    Last Post: 10th December 2009, 10:06
  4. multiple QTimer::singleShot() calls?
    By mattc in forum Qt Programming
    Replies: 1
    Last Post: 27th July 2009, 19:22
  5. Can we connect QTimer::SingleShot with a slot taking arguments?
    By maverick_pol in forum Qt Programming
    Replies: 4
    Last Post: 17th September 2008, 18:02

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.