У меня большой проект с графическим интерфейсом, и я хочу управлять некоторыми файлами в фоновом режиме.Я реализовал новый поток для этой задачи, и во время выполнения все прекрасно работает.Но как только я закрываю приложение, visual-leak-detector
обнаруживает 3-7 утечек памяти.
Я отделил свой многопоточный код и создал новый проект, чтобы проверить это на примере минимального кода, но я все еще не могучтобы исправить мою проблему.
Я думаю, что это как-то связано с циклом событий основной программы.Возможно, цикл не обрабатывает последние события для удаления моего класса потока и самого потока.Потому что я остановился и вышел из потока в деструкторе.Но я не уверен в этом.
Вот мой минимальный код: threadclass.hpp:
#include <QObject>
#include <QDebug>
class ThreadClass : public QObject {
Q_OBJECT
public:
explicit ThreadClass() {}
virtual ~ThreadClass(){
qDebug() << "ThreadClass Destructor";
}
signals:
// emit finished for event loop
void finished();
public slots:
// scan and index all files in lib folder
void scanAll(){
for(long i = 0; i < 10000; i++){
for (long k = 0; k < 1000000; k++);
if(i%500 == 0)
qDebug() << "thread: " << i;
}
}
// finish event loop and terminate
void stop(){
// will be processed after scanall is finished
qDebug() << "STOP SIGNAL --> EMIT FINSIHED";
emit finished();
}
};
threadhandler.hpp:
#include <QObject>
#include <QThread>
#include "threadclass.hpp"
class ThreadHandler : public QObject {
Q_OBJECT
public:
explicit ThreadHandler(QObject *parent = 0) : parent(parent), my_thread(Q_NULLPTR) {}
virtual ~ThreadHandler() {
// TODO Check!
// I think I don't have to delete the threads, because delete later
// on finish signal. Maybe I just have to wait, but then how do I
// check, if thread is not finished? Do I need to make a bool var again?
if (my_thread != Q_NULLPTR && my_thread->isRunning())
{
emit stopThread();
//my_thread->quit();
my_thread->wait();
//delete my_thread;
}
qDebug() << "ThreadHandler Destructor";
my_thread->dumpObjectInfo();
}
void startThread(){
if (my_thread == Q_NULLPTR)
{
my_thread = new QThread;
ThreadClass *my_threaded_class = new ThreadClass();
my_threaded_class->moveToThread(my_thread);
// start and finish
QObject::connect(my_thread, &QThread::started, my_threaded_class, &ThreadClass::scanAll);
QObject::connect(this, &ThreadHandler::stopThread, my_threaded_class, &ThreadClass::stop);
// finish cascade
// https://stackoverflow.com/a/21597042/6411540
QObject::connect(my_threaded_class, &ThreadClass::finished, my_threaded_class, &ThreadClass::deleteLater);
QObject::connect(my_threaded_class, &ThreadClass::destroyed, my_thread, &QThread::quit);
QObject::connect(my_thread, &QThread::finished, my_thread, &QThread::deleteLater);
my_thread->start();
}
}
signals:
void stopThread();
private:
QObject *parent;
QThread* my_thread;
};
Основной.cpp дрянной, но, похоже, достаточно хорошо имитирует поведение моей основной программы:
#include <QCoreApplication>
#include <QTime>
#include <QDebug>
#include "threadhandler.hpp"
#include <vld.h>
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
ThreadHandler *th = new ThreadHandler();
th->startThread();
// wait (main gui programm)
QTime dieTime= QTime::currentTime().addSecs(5);
while (QTime::currentTime() < dieTime) {
QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
}
qDebug() << "DELETE TH";
delete th;
qDebug() << "FINISH ALL EVENTS";
QCoreApplication::processEvents(QEventLoop::AllEvents, 500);
qDebug() << "QUIT";
QCoreApplication::quit();
qDebug() << "CLOSE APP";
// pause console
getchar();
// return a.exec();
}
Вот вывод из VLD:
WARNING: Visual Leak Detector detected memory leaks!
...
turns out this is very boring and uninteresting
...
Visual Leak Detector detected 3 memory leaks (228 bytes).
Largest number used: 608 bytes.
Total allocations: 608 bytes.
Visual Leak Detector is now exiting.
The program '[8708] SOMinimalExampleThreads.exe' has exited with code 0 (0x0).
Обновление 1: Я добавил qDebug() << "ThreadClass Destructor";
к деструктору ThreadClass
, и мой новый вывод выглядит так:
...
thread: 9996
thread: 9997
thread: 9998
thread: 9999
ThreadHandler Destructor
FINISH ALL EVENTS
CLOSE APP
Теперь ясно, что деструктор моего многопоточного класса никогда не вызывается и поэтому теряется внедействительным.Но тогда почему это не работает?
QObject::connect(my_threaded_class, &ThreadClass::finished, my_threaded_class, &ThreadClass::deleteLater);
Обновление 2: Я нашел одну проблему в ThreadHandler:
emit stopThread();
my_thread->quit(); // <-- stops the event loop and therefore no deletelater
my_thread->wait();
Я удалил my_thread->quit()
и теперьвызывается деструктор ThreadClass, но my_thread->wait()
никогда не заканчивается.