Why QThread still working, when work is done?
-
Hi,
I have simple app with 2 threads: main and one for heavy calculations.
When the calculations are in progress I close app using X button. So my code goes to MainWindow destructor and I have here:
thread->quit(); qInfo()<<"BEFORE WAIT"; thread->wait(); qInfo()<<"AFTER WAIT";
I quit second thread, so my second thread exit event loop. But of course it still calculates. On main thread I wait on line
thread->wait()
. But when the second thread ends calculates ( I see on debuq "END" ), I think the second thread did the work, there is no event loop in second thread, so work for second thread is over. But I still wait onthread->wait()
. And I will wait forever... Why this is happening?My whole code:
MainWindow ( main thread ) :constructor: thread = new QThread(this); worker = new Worker; connect(this, &MainWindow::start, worker, &Worker::calculate); worker->moveToThread(thread); thread->start(); emit start(); destructor: thread->quit(); qInfo()<<"BEFORE WAIT"; thread->wait(); qInfo()<<"AFTER WAIT";
Second thread ( heavy calculations ) :
void Worker::calculate() { double z = 21; for(int i=0;i<100000000;i++) { if(i%5000000 == 0) // to see that thread works { QCoreApplication::processEvents(); qDebug()<<i; } z+=qSin(i*0.32)*qCos(i/2*0.31); // some heavy calculations z+=10.00/(i+1); } qInfo()<<"END"; }
And my debuq:
0 5000000 10000000 15000000 20000000 25000000 BEFORE WAIT 30000000 35000000 40000000 45000000 50000000 55000000 60000000 65000000 70000000 75000000 80000000 85000000 90000000 95000000 END 13:58:51: The program has unexpectedly finished. // because I stop program using Qt Creator
-
Hi,
I have simple app with 2 threads: main and one for heavy calculations.
When the calculations are in progress I close app using X button. So my code goes to MainWindow destructor and I have here:
thread->quit(); qInfo()<<"BEFORE WAIT"; thread->wait(); qInfo()<<"AFTER WAIT";
I quit second thread, so my second thread exit event loop. But of course it still calculates. On main thread I wait on line
thread->wait()
. But when the second thread ends calculates ( I see on debuq "END" ), I think the second thread did the work, there is no event loop in second thread, so work for second thread is over. But I still wait onthread->wait()
. And I will wait forever... Why this is happening?My whole code:
MainWindow ( main thread ) :constructor: thread = new QThread(this); worker = new Worker; connect(this, &MainWindow::start, worker, &Worker::calculate); worker->moveToThread(thread); thread->start(); emit start(); destructor: thread->quit(); qInfo()<<"BEFORE WAIT"; thread->wait(); qInfo()<<"AFTER WAIT";
Second thread ( heavy calculations ) :
void Worker::calculate() { double z = 21; for(int i=0;i<100000000;i++) { if(i%5000000 == 0) // to see that thread works { QCoreApplication::processEvents(); qDebug()<<i; } z+=qSin(i*0.32)*qCos(i/2*0.31); // some heavy calculations z+=10.00/(i+1); } qInfo()<<"END"; }
And my debuq:
0 5000000 10000000 15000000 20000000 25000000 BEFORE WAIT 30000000 35000000 40000000 45000000 50000000 55000000 60000000 65000000 70000000 75000000 80000000 85000000 90000000 95000000 END 13:58:51: The program has unexpectedly finished. // because I stop program using Qt Creator
@qwe3 said in Why QThread still working, when work is done?:
I quit second thread, so my second thread exit event loop.
Calling
quit()
tells the event loop to stop running. However, it has no effect on your for-loop.If you want to interrupt the calculation, then you must call
break;
from inside your for-loop. -
@JKSH Thank you for answer. I know that I have to use
isInterruptionRequested()
andrequestInterruption()
. But now I ask about something different.I would like ( now ) to have an application, which calculate what I want ( calculate() method in second thread ) even if I close the application. But when it finish calculates, application should close in correct way. And now ( my code ) I have situation that my application wait to finish calculates, but when they are finished, my application still is running ( I wait on
thread->wait
).Maybe when I quit event loop in second thread, this thread doesn't send
finished()
signal and I will wait inthread->wait()
forever?I ask about it, not to solved a problem, but to understand how quit() works, and why I have to still wait on
thread->wait
-
@JKSH The problem is
QCoreApplication::processEvents();
When I delete this line from my code - everything is ok. When this line is in my code - I wait in
thread->wait()
forever. Why? -
@JonB Using
processEvents()
doesn't make sense in my code. I tried something different and accidentally add this method. And now I would like to know, what's going on.Can you explain me what means
It's probably hanging in that when the main UI thread has gone away/is no longer running the UI loop.
?I know there is an event loop, which is in the main.cpp file:
return a.exec();
So when I close app and my code is in mainWindow's destructor I can't receive signals, because mainWindow is no longer in
a.exec()
?EDIT:
I don't see link between
processEvents()
andIt's probably hanging in that when the main UI thread has gone away/is no longer running the UI loop.
-
This works fine for me:
class Worker : public QObject { public: void calculate() { QThread::sleep(20); QCoreApplication::processEvents(); } }; class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow() { thread = new QThread(this); worker = new Worker; worker->moveToThread(thread); thread->start(); QTimer::singleShot(0, worker, &Worker::calculate); } ~MainWindow() { thread->quit(); thread->wait(); } private: QThread *thread; Worker *worker; }; int main(int argc, char **argv) { QApplication app(argc, argv); MainWindow mw; mw.show(); return app.exec(); } #include "main.moc"
Please provide a minimal compilable example.
-
@Christian-Ehrlicher Your code is ok?
I think I can't add parent to
worker = new Worker(this);
I have error:
QObject::moveToThread: Cannot move objects with a parent
EDIT:
When I delete parent I get the same situation: I wait onthread->wait()
EDIT2:
My code:int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); } MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); thread = new QThread(this); worker = new Worker; worker->moveToThread(thread); thread->start(); QTimer::singleShot(0, worker, &Worker::calculate); } MainWindow::~MainWindow() { thread->quit(); qInfo()<<"BEFORE WAIT"; thread->wait(); qInfo()<<"AFTER WAIT"; delete ui; } void Worker::calculate() { QThread::sleep(20); qInfo()<<"AFTER SLEEP"; QCoreApplication::processEvents(); }
-
@Christian-Ehrlicher Your code is ok?
I think I can't add parent to
worker = new Worker(this);
I have error:
QObject::moveToThread: Cannot move objects with a parent
EDIT:
When I delete parent I get the same situation: I wait onthread->wait()
EDIT2:
My code:int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); } MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); thread = new QThread(this); worker = new Worker; worker->moveToThread(thread); thread->start(); QTimer::singleShot(0, worker, &Worker::calculate); } MainWindow::~MainWindow() { thread->quit(); qInfo()<<"BEFORE WAIT"; thread->wait(); qInfo()<<"AFTER WAIT"; delete ui; } void Worker::calculate() { QThread::sleep(20); qInfo()<<"AFTER SLEEP"; QCoreApplication::processEvents(); }
@qwe3 said in Why QThread still working, when work is done?:
@Christian-Ehrlicher Your code is ok?
You're right, it was a slightly outdated version. Adjusted my code but still works fine.
Your code is not compilable at all so I can't test yours. Please provide a minimal compilable example similar to mine without any ui file or other unneeded stuff. -
Code:
#include <QApplication> #include <QThread> #include <QTimer> #include <QMainWindow> #include <QDebug> class Worker : public QObject { public: void calculate() { qInfo()<<"START SECOND THREAD"; QThread::sleep(20); QCoreApplication::processEvents(); qInfo()<<"END SECOND THREAD"; } }; class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow() { thread = new QThread(this); worker = new Worker; worker->moveToThread(thread); thread->start(); QTimer::singleShot(0, worker, &Worker::calculate); } ~MainWindow() { thread->quit(); qInfo()<<"before"; thread->wait(); qInfo()<<"after"; } private: QThread *thread; Worker *worker; }; int main(int argc, char **argv) { QApplication app(argc, argv); MainWindow mw; mw.show(); return app.exec(); } #include "main.moc"
I only add libraries and debuq. So I start app and after 5 second I close app using X button. Now I wait additional 15 seconds and see on debug
END SECOND THREAD
. And my app is still running. I have to close it in Qt Creator clicking red square. And have information:21:03:25: The program has unexpectedly finished.
I don't see on debug
after
-
Works fine for me with Qt5.15 on linux but have the same effect on windows. Maybe it's worth opening a Qt bug report.
-
@Christian-Ehrlicher Thank you for help, but I don't understand this:
but have the same effect on windows
Which option:
- On linux everything is ok, but on windows you have the same problem like me
- On linux and windows everything is ok
?
-
@Christian-Ehrlicher Thank you for help, but I don't understand this:
but have the same effect on windows
Which option:
- On linux everything is ok, but on windows you have the same problem like me
- On linux and windows everything is ok
?
@qwe3 Since @Christian-Ehrlicher suggested to open a bug report it works on Linux but not on Windows (in case 2 there would not be any need to file a bug report).