【问题标题】:QEventLoop proper usageQEventLoop 正确使用
【发布时间】:2015-06-09 13:39:29
【问题描述】:

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

【问题讨论】:

  • 你想在第二种情况下如何中断事件循环?首先是可以的,但你也应该处理错误。
  • 是的,这就是我所担心的,所以我改变了它。我只是不确定我的想法是否正确,所以我问了
  • 一般你都不应该使用——QApplication已经为主线程设置了一个事件循环,而QThread为后台线程设置了一个事件循环。
  • 本地 QEventLoops 是万恶之源。 (因为所有类型的事情都可能在 loop.exec() 返回之前发生)。连接完成到另一个插槽,然后继续。
  • 我同意弗兰克的观点,在这种情况下使用事件循环似乎太过分了,可能会产生复杂的问题

标签: qt qtnetwork qeventloop


【解决方案1】:

我同意@Mher-Didaryan 的观点——事件循环由第二个代码 sn-p 中的代码行 loop.exec(); 开始——永远不会退出。这是因为 SIGNAL 和 SLOT 之间的 connect() 是针对与通过 EventLoop loop; 指示的事件循环不同的事件循环完成的。

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

    connect(manager, SIGNAL(finished(QNetworkReply*)),&loop, SLOT(quit()));

可以在manager->get( request ) ; 发出finished(QNetworkReply*) 信号后执行。也许它可能发生在涉及非常小的文件或响应的 GET 类型的 HTTP 操作中。在这种情况下,由第一个代码 sn-p 中的 loop.exec(); 启动的事件循环也不会退出。我想这也是@Mher-Didaryan 在他的回答中提出的问题。

也许您也可以使用下面的 QEventLoop 逻辑来处理以下负面执行场景

  1. GET 请求超时(比如由于网络连接问题)
  2. 来自网络服务器端的错误类型响应

    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;
    

【讨论】:

  • 如果第一个为真,QNetworkAccessManager不会被删除。
  • QWaitCondition: 在线程仍在等待时销毁是可能的
【解决方案2】:

在您的第二个示例中,事件循环永远不会退出,而在您的第一个示例中,循环将在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*)) 的情况。

【讨论】:

    猜你喜欢
    • 2018-05-06
    • 2012-05-28
    • 2013-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-22
    • 2014-02-20
    相关资源
    最近更新 更多