QNetworkAccessManager即使在另一个线程中也会冻结GUI

时间:2019-06-06 02:27:08

标签: c++ qt qthread qnetworkaccessmanager

程序打开后,将通过QNetworkAccessManager::connectToHostEncrypted()的服务器建立连接,该连接在MainWindow的构造函数中调用。这将冻结GUI线程,并导致明显的延迟,直到连接完成。 (有时要花整整一秒钟的时间)

该问题由于我的程序在启动时淡入而变得更糟,因此,在GUI线程被阻止时,直到连接完成后才开始淡入。在默认的Qt项目中,这可以通过其他方式看到,例如未绘制小部件。

为了保持GUI线程的运行,我将QNetworkAccessManager移到了一个完全不同的线程中,QThread认为这可以解决问题,但是GUI线程仍然冻结。这对我来说毫无意义。

这是一个最少可编译的示例项目。

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QNetworkAccessManager>
#include <QThread>

class Connection : public QNetworkAccessManager
{
    Q_OBJECT
public:
    Connection(QObject *parent) : QNetworkAccessManager(parent){}

public slots:
    void openConnection(){
        connectToHostEncrypted("https://www.url.com");
    }

signals:
    void closeThread(bool);
};


namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;

    QThread *connectionThread;
    Connection *connection;
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    connection = new Connection(this);

    connectionThread = new QThread();
    connection->moveToThread(connectionThread);
    connect(connectionThread, SIGNAL(started()), connection, SLOT(openConnection()));
    connect(connection, SIGNAL(closeThread(bool)), connectionThread, SLOT(quit()));
    connect(connectionThread, SIGNAL(finished()), connectionThread, SLOT(deleteLater()));

    connectionThread->start();
}

MainWindow::~MainWindow()
{
    delete connection;
    delete ui;
}

这个示例项目创建了Connection的一个实例,它是QNetworkAccessManager的子类,然后我通过moveToThread()移到另一个线程。这就是我所有工作线程的处理方式。

发出线程的start()信号时,openConnection()调用GUI线程冻结的地方connectToHostEncrypted()

我尝试仅调用常规HTTP请求,但是问题仍然存在,因为仍然需要进行初始连接。

即使连接是在另一个线程中完成的,GUI线程为什么仍然冻结?

2 个答案:

答案 0 :(得分:1)

尝试使用:

connect(connectionThread, SIGNAL(started()), connection, SLOT(openConnection(),Qt::QueuedConnection);

答案 1 :(得分:1)

问题是我将this作为父级传递给Connection实例,这意味着moveToThread()无法完成。我只需要检查输出日志就可以看到它,但是我一定错过了!

通过删除该父对象,该连接现在位于其自己的线程中。

我通过在QThread::sleep(3)调用中调用openConnection()进一步测试了这一点,仍然没有延迟。