How can I wait all request complate?
-
There is a continuous data arrival to my Class1 class. I want to get another list by sending myArray list in the doSth function of Class1 to the getList function of Class2.
Class2 should return me a list by making GET and PUT requests in the getList function. But I want to wait until these requests are completed, how can I do that?
I have classes and structs
//Class4
struct Class4{ int a; int b; }
//Class3
struct Class3{ QString name; }
//Class2
#include "class3.h" #include "class4.h" enum Type{ type1, type2, type3 } class Class2:public QObject{ Class2(){ manager.setAutoDeleteReplies(true); } ~Class2(){ reply->deleteLater(); } QList<Class4> getList(QList<Class3> array){ myList.clear(); process1(1); for(Class3 class3 : array){ process2(class3.name); getData(); } process2("Joe Doe"); process1(2); return myList; } private slots: void onReadReady(){ if(type == Type::type3){ data += reply->readAll(); } } void onFinished(){ if(type == Type::type3){ Class4 class4 = getClass(data); myList.append(class4); } } private: void process1(int mode){ type = Type::type1; QJsonObject data; data["mode"] = mode; QJsonDocument doc(data); QByteArray body = doc.toJson(); QUrl url("http/url"); QNetworkRequest request(url); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); reply = manager.put(request, body); connect(reply, &QNetworkReply::readyRead, this, &Class2::onReadReady); connect(reply, &QNetworkReply::finished, this, &Class2::onFinished); } void process2(QString name){ type = Type::type2; QJsonObject data; data["name"] = name; QJsonDocument doc(data); QByteArray body = doc.toJson(); QUrl url("http/url2"); QNetworkRequest request(url); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); reply = manager.put(request, body); connect(reply, &QNetworkReply::readyRead, this, &Class2::onReadReady); connect(reply, &QNetworkReply::finished, this, &Class2::onFinished); } void getData(){ type = Type::type3; QUrl url("http/url3"); QNetworkRequest request(url); reply = manager.get(request); connect(reply, &QNetworkReply::readyRead, this, &Class2::onReadReady); connect(reply, &QNetworkReply::finished, this, &Class2::onFinished); } Class4 getClass(QByteArray data){ Class4 class4; if(data.isNull() || data.size() <= 4){ return class4; } QJsonDocument document = QJsonDocument:: fromJson(data); QJsonObject rootObj = document.object(); class4.a= rootObj["a"].toInt(); class4.b= rootObj["b"].toInt(); return class4; } private: QNetworkReply *reply; QNetworkAccessManager manager; QByteArray data; QList<Class4> myArray; Type type = Type::type1; }
//Class1
#include "class2.h" #include "class3.h" #include "class4.h" class Class1 : public QObject{ Class1(); ~Class1(); public slots: void doSth(QByteArray data){ ... //I want to wait here for response all request QList<Class4> result = class2.getList(myArray); ... } private: Class2 class2; QList<Class3> myArray; }
//main
#include "class1.h" int main(){ Class1 class1; while(true){ class1.doSth(data); } }
-
@Joe-von-Habsburg
Leaving aside that yourmain()
is no good for a Qt program, you have not created any Qt application instance and you should start the event loop. But I will stick to the nub of the question.This is a similar/related question to the currently on-going discussion in https://forum.qt.io/topic/155475/avoiding-event-loop-blockage-in-qt-applications, which you might like to read.
The way most of us as Qt users would do it is not to wait till requests are complete. Instead we would write the code to execute after the response is received in a slot attached to
QNetworkReply::finished
. Do you see how that avoids any "while" loops and "waiting"? If necessary we would maintain state for where we got to and/or a queue of further requests to work through. This is the "event-driven" paradigm espoused by Qt and other similar systems.But if you really want to write your code to "block" and "wait" for a response, use a local
QEventLoop
instance and callexec()
. This is at least an "efficient" way to do it. A couple of examples on stackoverflow illustrating just this for yourQNetworkReply::finished
case:
https://stackoverflow.com/questions/29449561/qeventloop-proper-usage
https://stackoverflow.com/questions/54694312/qeventloop-wait-for-only-local-events-not-main-loop-eventsThis is the paradigm:
QEventLoop localEventLoop; QNetworkAccessManager manager; QNetworkReply *reply = manager.get(QNetworkRequest(QUrl("http://example.com"))); QObject::connect(reply, &QNetworkReply::finished, &localEventLoop, &QEventLoop::quit); localEventLoop.exec(); // We do not get here until `QNetworkReply::finished` signal has been received, which quits the event loop
-
@JonB said in How can I wait all request complate?:
main() is no good for a Qt program
I gave main() as an example. To show that there is a continuous data flow to the doSth function.
@JonB said in How can I wait all request complate?:
But if you really want to write your code to "block" and "wait" for a response, use a local QEventLoop instance and call exec(). This is at least an "efficient" way to do it. A couple of examples on stackoverflow illustrating just this for your QNetworkReply::finished case:
https://stackoverflow.com/questions/29449561/qeventloop-proper-usage
https://stackoverflow.com/questions/54694312/qeventloop-wait-for-only-local-events-not-main-loop-eventsThank you I will look them