Правильный способ закрыть 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()
и все должно быть правильно вычищено.
Пожалуйста, дайте мне знать, если это решит вашу проблему. Если нет, может быть другая рыба, чтобы жарить.