I'm making a Qt5 QCoreApplication for downloading files from FTP servers (started at HTTP, now switched).
I encounter a problem when my program is to be closed. After I added exit(0)
into downloader.cpp
, my program is now ending, but I get the following error :
QWaitCondition: Destroyed while threads are still waiting.
My code is as follows :
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);
}
I get the following output :
Download Finished! Downloaded file size... QWaitCondition: Destroyed while threads are still waiting.
As far as I can notice, everything I imagined is done. File is downloaded, and its size is presented. But I guess this error must mean something.
Can somebody explain to me what this error is, why is it occurring and how to patch it?
You have some problems with your code. You are treating Qt like it is procedural in nature whereas it is actually event-driven via a main loop.
First, it is wrong to call qApp->exit(0)
before the QApplication
loop is started. According to Qt, "If the event loop is not running, this function does nothing." Your event loop is not yet running because you called doDownload
before you called exec
Second, by the time you ran QApplication::exec
, you have not yet created any top-level windows or events to dispatch. I am not sure what is supposed to happen when you call exec
with no work to do. Semantically, of course, the call to exec
does nothing. Technically... perhaps it could lead to thread errors. Again, I am not sure, but I know that you are not supposed to use exec
in this manner.
Run your main event loop before doing all your fancy Qt stuff. This allows Qt to call into your code. Add a slot, doDownload
and a signal, finished
to your 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();
}
Then call your slot after inversion of control has been established by calling exec
and starting the main loop:
#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();
}
Now Qt will call into your code. Instead of explicitly exiting the application, simply emit finished()
and everything should be cleaned up correctly.
Please let me know if this solves your issue. If not, there may be other fish to fry.