QNetworkAccessManager замораживает графический интерфейс даже в другом потоке - PullRequest
0 голосов
/ 06 июня 2019

Когда моя программа открывается, устанавливается соединение с моим сервером через QNetworkAccessManager::connectToHostEncrypted(), который вызывается в конструкторе MainWindow.Это замораживает поток 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() вызывает connectToHostEncrypted(), где поток GUI зависает.

Я пыталсявместо этого просто вызывая обычный HTTP-запрос, однако проблема не устранена, поскольку все еще необходимо установить исходное соединение.

Почему поток GUI по-прежнему зависает, даже если соединение выполняется в другом потоке?

Ответы [ 2 ]

1 голос
/ 06 июня 2019

Проблема была в том, что я передал this в качестве родителя экземпляру Connection, что означало, что moveToThread() не может быть завершено. Я просто должен был проверить выходной журнал, чтобы увидеть это, но я, должно быть, пропустил его!

После удаления этого родителя соединение было теперь в его собственном потоке.

Я также проверил это, вызвав QThread::sleep(3) внутри этого openConnection() звонка, и задержки все еще не было.

1 голос
/ 06 июня 2019

попробуйте использовать:

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