Stop a QThread befor quitting application
-
Hi,
I have toubles stopping a QThread when i quit the application.
I designed a class ProgramParser that will parse very long text files.
I have another class ThreadSafeParser that is my interface to use a ProgramParser object in a dedicated QThread through Signal/Slots so my GUI is not blocked during parsers work
// ThreadSafeParser ctor parserThread = new QThread(this); parser = new ProgramParser(); parser->moveToThread(parserThread);
So far, OK. Then I put an instance of ThreadSafeParser as contextProperty to use it from QML.
And connect QGuiApplication aboutToQuit signal to ThreadsafeParser s safeQuit slot.
if not, parser will still work even if i quit the app.ThreadsafeParser parser; engine.rootContext()->setContextProperty("parser",&parser); QObject::connect(qApp,&QGuiApplication::aboutToQuit,&parser,&ThreadsafeParser::safeQuit);
this is the content of my safeQuit method
parserThread->quit(); parserThread->wait();
and this is my ThreadsafeParser destructor
~ThreadsafeParser(){ parserThread->quit(); parserThread->wait(); }
with this method the thread is now stopped but applications will quit with code 1073741845
I also tryed to call deleteLater instead of my own safeQuit method, in this case work in progress will not even stop.
Please tell me what i'm doing wrong.
-
WORKING VERSION
class ProgramParser : public QObject { Q_OBJECT public: /// Ctor explicit ProgramParser(QObject *parent = nullptr); public slots: void openFile(QString filePath,int ind); void startParsing();// long task };
class ThreadsafeParser : public QObject { Q_OBJECT QThread *parserThread; ProgramParser *parser; public: explicit ThreadsafeParser(QObject *parent = nullptr); ~ThreadsafeParser(){ qDebug()<<"QUITTING THE QTHREAD"; // parserThread->quit(); // not needed parserThread->deleteLater(); } signals: void s_parse(); public slots: /// Demande de commancer à parser les fichiers void startParsing(){ emit s_parse(); } }; ThreadsafeParser::ThreadsafeParser(QObject *parent) : QObject(parent) { parserThread = new QThread();// QThread(this); parser = new ProgramParser; parser->moveToThread(parserThread); // QObject::connect(parserThread, &QThread::finished, parser, &QObject::deleteLater); /// forward SIGNALs QObject::connect(this,&ThreadsafeParser::s_parse,parser,&ProgramParser::startParsing); parserThread->start(); }
int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); QQmlApplicationEngine engine; ThreadsafeParser safeParser; // no neeed to handle this //QObject::connect(qApp,&QGuiApplication::aboutToQuit,&safeParser,&ThreadsafeParser::deleteLater); engine.rootContext()->setContextProperty("parser",&safeParser); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); if (engine.rootObjects().isEmpty()) return -1; return app.exec(); }
Output in qt creator when i quit the app :
Y : -178.062 // parse result X : 65.4623 // parse result Y : -178.09 // parse result QUITTING THE QTHREAD // destructor called... 10:54:45: C:/.../JobPlan exited with code 0
-
Hi,
Out of curiosity, why do that from two different places ?
Unless something goes wrong, the destructor will be called anyway and again unless something wrong, aboutToQuit also, therefore it's a bit redundant.
-
@SGaist said in Stop a QThread befor quitting application:
why do that from two different places
i do from one or the other
i first tryed to call only deleteLaterQObject::connect(qApp,&QGuiApplication::aboutToQuit,&parser,&ThreadsafeParser::deleteLater );
and expected this to be called
~ThreadsafeParser(){ parserThread->quit(); parserThread->wait(); }
but application is exiting with code 1073741845
then i have created my safeQuit method
QObject::connect(qApp,&QGuiApplication::aboutToQuit,&parser,&ThreadsafeParser::safeQuit ); ... void safeQuit(){ parserThread->quit(); parserThread->wait(); }
in this case parser is still parsing if i quit app.
tomorrow i will try to set parserThread = nullptr as @J-Hilk suggested
~ThreadsafeParser(){ parserThread->quit(); parserThread->wait(); parserThread = nullptr }
thx for the interest
-
How is that ThreadsafeParser object handled ?
Because I just realised that you are potentially creating a double delete with your deleteLater call since it seems that
parser
is an object that's on the stack. -
@SGaist said in Stop a QThread befor quitting application:
How is that ThreadsafeParser object handled ?
i create one in my main cpp thats all
ThreadsafeParser parser; engine.rootContext()->setContextProperty("parser",&parser); QObject::connect(qApp,&QGuiApplication::aboutToQuit,&parser,&ThreadsafeParser::safeQuit);
-
Then, no it's on the stack as I was talking about your
ThreadsafeParser
object which is also called parser (this is way using clear variable names is very important). -
Hi,
I came back to the official example (i read it long time ago and was able to design multiple multithreaded application since. Now for some reason i'm stuck ): https://doc.qt.io/qt-5/qthread.html#detailsI do exactly the same thing, My ProgramParser is the Worker of the example.
And my ThreadsafeParser is the Controller.then i my main i just connect app's quit signal to deleteLater slot of My 'Controller' aka ThreadsafeParser
QObject::connect(qApp,&QGuiApplication::aboutToQuit,&safeParser,&ThreadsafeParser::deleteLater);
so this must be called right ?
~ThreadsafeParser(){ qDebug()<<"QUITTING THE QTHREAD"; parserThread.quit(); parserThread.wait(); }
and since my parserThread 's finished is connected to my ProgramParser (Worker) deleteLater
QObject::connect(&parserThread, &QThread::finished, parser, &QObject::deleteLater);
I expect this to quit cleanly, but when i quit , the work is still in progress
edit
i changed the destructor to
~ThreadsafeParser(){ parserThread->deleteLater(); }
and putted parserThread on heap instead of stack
and passed ProgramParser *parser; to member instead of creating it in ThreadsafeParser's ctornow QThread is stopped (it looks like) but application don't quit cleanly, i got : app crashed message.
Can this be related to the compiler i use, i did the exact same thing more than 10 times and it worked perfectly with MinGw compilers, for this project i have to use MSVC17 32bit
This is the only difference i see -
WORKING VERSION
class ProgramParser : public QObject { Q_OBJECT public: /// Ctor explicit ProgramParser(QObject *parent = nullptr); public slots: void openFile(QString filePath,int ind); void startParsing();// long task };
class ThreadsafeParser : public QObject { Q_OBJECT QThread *parserThread; ProgramParser *parser; public: explicit ThreadsafeParser(QObject *parent = nullptr); ~ThreadsafeParser(){ qDebug()<<"QUITTING THE QTHREAD"; // parserThread->quit(); // not needed parserThread->deleteLater(); } signals: void s_parse(); public slots: /// Demande de commancer à parser les fichiers void startParsing(){ emit s_parse(); } }; ThreadsafeParser::ThreadsafeParser(QObject *parent) : QObject(parent) { parserThread = new QThread();// QThread(this); parser = new ProgramParser; parser->moveToThread(parserThread); // QObject::connect(parserThread, &QThread::finished, parser, &QObject::deleteLater); /// forward SIGNALs QObject::connect(this,&ThreadsafeParser::s_parse,parser,&ProgramParser::startParsing); parserThread->start(); }
int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); QQmlApplicationEngine engine; ThreadsafeParser safeParser; // no neeed to handle this //QObject::connect(qApp,&QGuiApplication::aboutToQuit,&safeParser,&ThreadsafeParser::deleteLater); engine.rootContext()->setContextProperty("parser",&safeParser); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); if (engine.rootObjects().isEmpty()) return -1; return app.exec(); }
Output in qt creator when i quit the app :
Y : -178.062 // parse result X : 65.4623 // parse result Y : -178.09 // parse result QUITTING THE QTHREAD // destructor called... 10:54:45: C:/.../JobPlan exited with code 0
-
... I only removed :
- my own deletion handling (QObject::connect(qApp,&QGuiApplication::aboutToQuit,&safeParser,&ThreadsafeParser::deleteLater))
- the parserThread->quit() line in my destructor
- and the this i was passing to parserThread : (parserThread = new QThread(
this);)
now this works perfectly. Exit with code 0.
//QObject::connect(qApp,&QGuiApplication::aboutToQuit,&safeParser,&ThreadsafeParser::deleteLater); // no need // parserThread->quit(); //no need this in the destructor
I will update the la code i pasted.