3

I am working on an small client-server application. The client sends a query and has to wait for an answer. I think the most convenient way is to use a QEventLoop:

connect(&parser, SIGNAL(answer_received()), this, SLOT(react_to_answer()));
...
...
QEventLoop loop;
connect(&parser, SIGNAL(answer_received()), &loop, SLOT(quit()));
this.sendQuery();
loop.exec();

This worked for me at the moment, but what happens, if the signal answer_received() is emitted very fast, even before loop.exec() was called? Will my application stuck in the QEventLoop forever?

Thank you!

Louis Langholtz
  • 2,913
  • 3
  • 17
  • 40
Horst
  • 325
  • 3
  • 9
  • 1
    In about all event-driven GUI systems (including JavaScript in a browser, and the Windows API) the events do not happen asynchronously, but only when explicitly waited for by the code. While the code does someting else events may be queued up. I would be very much surprised if Qt is different in this respect. – Cheers and hth. - Alf Mar 04 '17 at 06:59
  • @Cheersandhth.-Alf Qt signals are not events and "generally" end up in synchronous direct calls. – Benjamin T Mar 04 '17 at 09:17
  • 1
    @Velkan Calling `QEventLoop::exec()` sets `QEventLoopPrivate::exit` to `false`, so calling `QEventLoop::quit()` does not prevent the event loop from running. – Benjamin T Mar 04 '17 at 09:27
  • @BenjaminT: False dichotomy. – Cheers and hth. - Alf Mar 04 '17 at 09:47
  • @Cheersandhth.-Alf Not that false, or your first comment would be true. Nothing in Qt prevents the `quit()` slot to be called during the `sendQuery()` call, especially because connections are much more like simple function calls than events. To ensure that `quit()` is called after `loop.exec()`, one would have to force going through Qt event system in some way, like explicitly specifying that the connection is queued. – Benjamin T Mar 04 '17 at 10:19

1 Answers1

4

Given your code, the only way you will encounter an issue is if the answer_received() signal is emitted before loop.exec() is called. Which is equivalent to say that answer_received() is emitted during the call to this.sendQuery();.

In your case it is not likely to happen because you rely on server/client interactions and you likely use a QNetworkAccessManager or a QSocket of some sort. If this is the case the QNetworkAccessManager/QSocket will not emit readyRead() or finished() signals until you enter the event loop.

However, in a more general case if answer_received() can be emitted from this.sendQuery() you have to change your code:

  1. You could make the connection between to be queued. This way even if answer_received() is emitted during this.sendQuery() the slot will not be called until you enter the event loop.

    connect(&parser, SIGNAL(answer_received()), &loop, SLOT(quit()), Qt::QueuedConnection);
    
  2. You could ensure that answer_received() is never emitted during this.sendQuery(). On way to do so is to use 0ms QTimer, which will trigger as soon as all events in the event queue are processed, i.e during loop.exec()

    Replace:

    emit answer_received();
    

    By:

    QTimer::singleShot(0, this, *receiver, &MyClass::answer_received);
    
Benjamin T
  • 8,120
  • 20
  • 37
  • Thank you very much, your answer makes sense. I had the concern you mentioned in the first sentence. – Horst Mar 04 '17 at 11:53