Правильный способ закрыть QCoreApplication

Я делаю Qt5 QCoreApplication для загрузки файлов с FTP-серверов (началось по HTTP, теперь переключено).

Я столкнулся с проблемой, когда моя программа должна быть закрыта. После того как я добавил exit(0) в downloader.cppмоя программа сейчас заканчивается, но я получаю следующую ошибку:

QWaitCondition: уничтожено, пока потоки все еще ждут.

Мой код выглядит следующим образом:

main.cpp

#include <QCoreApplication>
#include <downloader.h>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    Downloader d;
    d.doDownload();

    a.exec();
}


**downloader.cpp**

#include "downloader.h"

Downloader::Downloader(QObject *parent) :
    QObject(parent)
{
}

void Downloader::doDownload() {

manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));

manager->get(QNetworkRequest(QUrl("ftp://ftp.fao.org/Public/GIEWS/windisp/40manual/wd4en.pdf")));
}


void Downloader::replyFinished (QNetworkReply *reply)
{

    if(reply->error()) {
        qDebug() << "ERROR!";
        qDebug() << reply->errorString();
    }
    else

    {
        qDebug() << "Download finished!";

        QFile *file = new QFile("C:/Users/jelicicm/Desktop/wd4en.pdf");

        if(file->open(QFile::Append))
        {
            file->write(reply->readAll());
            file->flush(); file->close();
            qDebug() <<"Downloaded file size:" <<(file->size())/1024<<"KB";
        }
        delete file;
    }

    reply->deleteLater();
    exit(0);

}

Я получаю следующий вывод:

Загрузка завершена! Размер загруженного файла... QWaitCondition: уничтожено, пока потоки все еще ожидают.

Насколько я могу заметить, все, что я себе представлял, сделано. Файл загружен, и указан его размер. Но я думаю, что эта ошибка должна что-то значить.

Может кто-нибудь объяснить мне, что это за ошибка, почему она возникает и как ее исправить?

1 ответ

Решение

У вас есть проблемы с вашим кодом. Вы относитесь к Qt как к процедурному по своей природе, тогда как на самом деле он управляется событиями через основной цикл.

Во-первых, неправильно называть qApp->exit(0) перед QApplication цикл запущен. Согласно Qt: "Если цикл обработки событий не запущен, эта функция ничего не делает". Ваш цикл событий еще не запущен, потому что вы позвонили doDownload прежде чем ты позвонил exec

Во-вторых, к тому времени, как ты побежал QApplication::exec, вы еще не создали ни одного окна или события верхнего уровня для отправки. Я не уверен, что должно произойти, когда вы звоните exec без работы. Семантически, конечно, призыв к exec ничего не делает. Технически... возможно, это может привести к ошибкам потока. Опять же, я не уверен, но я знаю, что вы не должны использовать exec таким образом.

Запустите ваш главный цикл обработки событий, прежде чем делать все свои модные вещи в Qt. Это позволяет Qt вызывать ваш код. Добавить слот, doDownload и сигнал, finished на ваш Downloader,

class Downloader : public QObject 
{
  Q_OBJECT

public:
  Downloader(QObject * parent = nullptr);

private slots:
  void doDownload();

signals:
  void finished();
}

...

void Downloader::doDownload() 
{
  // Same implementation as before
  // Emit signal when finished
  emit finished();
}

Затем позвоните в ваш слот после того, как инверсия управления была установлена ​​путем вызова exec и запуск основного цикла:

#include <QCoreApplication>
#include "Downloader.h"

int main(int argc, char *argv[])
{
  QCoreApplication a(argc, argv);

  Downloader d;

  // Quit application when work is finished
  QObject::connect(&d, SIGNAL(finished()), &a, SLOT(quit())); // changed the 
  //variable name 'app' to 'a'

  // Run the user-hook (doDownload) from the application event loop.
  QTimer::singleShot(0, &d, SLOT(doDownload()));

  return a.exec();
}

Теперь Qt вызовет ваш код. Вместо того, чтобы явно выходить из приложения, просто emit finished() и все должно быть правильно вычищено.

Пожалуйста, дайте мне знать, если это решит вашу проблему. Если нет, может быть другая рыба, чтобы жарить.

Другие вопросы по тегам