Qt QEventLoop的正确用法

Qt QEventLoop的正确用法,qt,qtnetwork,qeventloop,Qt,Qtnetwork,Qeventloop,我怀疑我应该如何使用QEventLoop。我有两段代码,它们都适合我(下载web资源) 第一个: QNetworkAccessManager *manager = new QNetworkAccessManager( this ); QNetworkRequest request; request.setUrl(QUrl(url)); request.setRawHeader("User-Agent", "Mozilla Firefox"); connect(manager, SIGNAL(fi

我怀疑我应该如何使用
QEventLoop
。我有两段代码,它们都适合我(下载web资源)

第一个:

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()
?我在某处找到了第二个解决方案,但对我来说似乎不合适,所以我将其修改为第一段代码。

在第二个示例中,事件循环永远不会退出,而在第一个示例中,当
完成时(QNetworkReply*)
将退出。但是如果
manager->get(请求)怎么办导致
完成(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();

此外,您还需要以某种方式处理管理器根本不发出
信号(finished(QNetworkReply*)
的情况。

我同意@Mher Didaryan的观点-事件循环是通过以下代码行
loop.exec()开始的将永远不会退出。这是因为信号和插槽之间的connect()是针对不同的事件循环执行的,而不是通过
EventLoop循环指示的事件循环

在第一个代码段的情况下,逻辑取决于与向两个不同事件循环发出的一个相同GET请求相关联的
finished(QNetworkReply*)
信号。但很有可能

    connect(manager, SIGNAL(finished(QNetworkReply*)),&loop, SLOT(quit()));
可以在
manager->get(请求)之后执行发出了
完成(QNetworkReply*)
信号。对于涉及非常小的文件或响应的GET类型HTTP操作,可能会发生这种情况。在这种情况下,事件循环由
loop.exec()启动也不会退出。我猜这也是@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;
    

  • 在第二种情况下,您希望如何中断事件循环?第一个是可以的,但是你也应该处理错误。是的,这就是我一直担心的,所以我改变了它。我只是不确定我的想法是否正确,所以我问一般情况下你不应该使用这两种方法——QApplication已经为主线程设置了一个事件循环,而QThread为后台线程设置了一个事件循环。本地QEventLoop是万恶之源。(因为在loop.exec()返回之前,所有类型的事情都可能发生)。连接完成到另一个插槽,然后继续。我同意Frank的说法,在这种情况下使用eventloop似乎有点过头了,可能会产生复杂的问题QNetworkAccessManager不会在第一个插槽为true时被删除。QWaitCondition:在线程仍在等待时被销毁是可能的