【问题标题】:QNetworkAccessManager freezes GUI even when in another thread即使在另一个线程中,QNetworkAccessManager 也会冻结 GUI
【发布时间】:2023-04-06 11:44:01
【问题描述】:

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

这个问题因为我的程序在启动时淡入而变得更糟,所以当 GUI 线程被阻塞时,淡入直到连接完成后才会开始。在默认的 Qt 项目中,这在其他方面很明显,比如小部件没有被绘制。

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

这是一个最低限度可编译的示例项目。

主窗口.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

主窗口.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() 调用connectToHostEncrypted(),这是 GUI 线程冻结的地方。

我尝试只调用常规 HTTP 请求,但问题仍然存在,因为仍需要建立初始连接。

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

【问题讨论】:

    标签: c++ qt qthread qnetworkaccessmanager


    【解决方案1】:

    尝试使用:

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

    【讨论】:

    • 对不起,我做了一些进一步的测试,看起来使用 QueuedConnection 与解决方案无关。我的错。
    【解决方案2】:

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-10-16
      • 1970-01-01
      • 1970-01-01
      • 2015-10-23
      • 2012-10-25
      • 1970-01-01
      • 2016-07-05
      相关资源
      最近更新 更多