QEventLoop правильное использование
У меня есть сомнения, как мне использовать QEventLoop
, У меня есть 2 фрагмента кода, оба они работают для меня (скачайте веб-ресурс).
Первый:
QNetworkAccessManager *manager = new QNetworkAccessManager( this );
QNetworkRequest request;
request.setUrl(QUrl(url));
request.setRawHeader("User-Agent", "Mozilla Firefox");
connect(manager, SIGNAL(finished(QNetworkReply*)),this,SLOT(replyFinished(QNetworkReply*)));
manager->get( request ) ;
QEventLoop loop;
connect(manager, SIGNAL(finished(QNetworkReply*)),&loop, SLOT(quit()));
loop.exec();
Второй:
QNetworkAccessManager *manager = new QNetworkAccessManager( this );
QNetworkRequest request;
request.setUrl(QUrl(url));
request.setRawHeader("User-Agent", "Mozilla Firefox");
manager->get( request ) ;
QEventLoop loop;
connect(manager, SIGNAL(finished(QNetworkReply*)),this, SLOT(replyFinished(QNetworkReply*)));
loop.exec();
То, что я хочу знать, это то, что я должен использовать. Я имею в виду, завершается ли цикл обработки событий во втором после подачи сигнала? Или я должен позвонить quit()
как в первом? Я где-то нашел второе решение, но оно мне не показалось подходящим, поэтому я превратил его в первый кусок кода.
2 ответа
Я согласен с @Mher-Didaryan - что цикл событий начался с следующей строки кода loop.exec();
во втором фрагменте кода - никогда не выйдет. Это связано с тем, что connect() между SIGNAL и SLOT выполняется для цикла событий, отличного от цикла событий, указанного в EventLoop loop;
,
В случае 1-го фрагмента кода логика зависит от finished(QNetworkReply*)
сигнал, связанный с тем, что один и тот же запрос GET отправляется в два разных цикла событий. Но вполне возможно, что
connect(manager, SIGNAL(finished(QNetworkReply*)),&loop, SLOT(quit()));
вполне может выполнить после manager->get( request ) ;
выпустил finished(QNetworkReply*)
сигнал. Возможно, это может произойти для HTTP-операции типа GET, включающей очень маленький файл или ответ. В таком сценарии цикл событий начался loop.exec();
в 1-м фрагменте кода тоже не выйдет. Я думаю, это то, что @ Mher-Didaryan также спрашивает в своем ответе.
Может быть, вы можете использовать приведенную ниже логику QEventLoop, которая также будет обрабатывать следующие негативные сценарии выполнения
- Время ожидания запроса GET (скажем, из-за проблем с сетевым подключением)
Ошибка типа ответа со стороны сервера сети
QNetworkAccessManager *manager = new QNetworkAccessManager(this); QNetworkRequest request; QEventLoop loop; QTimer getTimer; // let's use a 10 second period for timing out the GET opn request.setUrl(QUrl(url)); request.setRawHeader("User-Agent", "Mozilla Firefox"); // connect the timeout() signal of getTimer object to quit() slot of event loop QTimer::connect(&getTimer,SIGNAL(timeout()),&loop, SLOT(quit())); QObject::connect(manager, SIGNAL(finished(QNetworkReply*)),&loop, SLOT(quit())); QNetworkReply *resp = manager->get( request ); getTimer.start(10000); // 10000 milliSeconds wait period for get() method to work properly loop.exec(); if(NULL == resp) { // Error. we probably timed out i.e SIGNAL(finished()) did not happen // this handles above indicated case (1) return -1; // or return some timeout related error value } else if( QNetworkReply::NoError != resp->error() ) { // Error - SIGNAL(finished()) was raised but get() opn failed & returned with error // Refer http://doc.qt.io/qt-4.8/qnetworkreply.html#NetworkError-enum // This section of code handles above indicated case (2) } else { // get() operation was Successful !. // read the response available in the 'resp' variable as a QString & parse it. // Obtain the necessary result and etc. } delete resp; delete manager;
Во втором примере цикл обработки событий никогда не завершится, с другой стороны, в первом примере цикл завершится, когда finished(QNetworkReply*)
излучает. Но что, если manager->get( request );
причина finished(QNetworkReply*)
сигнал, который должен быть передан, прежде чем вы подключите к нему цикл выхода?
QNetworkAccessManager *manager = new QNetworkAccessManager( this );
QNetworkRequest request;
QEventLoop loop;
request.setUrl(QUrl(url));
request.setRawHeader("User-Agent", "Mozilla Firefox");
connect(manager, SIGNAL(finished(QNetworkReply*)),this,SLOT(replyFinished(QNetworkReply*)));
connect(manager, SIGNAL(finished(QNetworkReply*)),&loop, SLOT(quit()));
manager->get( request ) ;
loop.exec();
А также нужно как-то справиться с ситуацией, когда менеджер не излучает SIGNAL(finished(QNetworkReply*))
совсем.