Solved How to close the programme when running a qtconcurrent from another thread
-
Hi,
The point of this question is only how to stop the programme if you are running QtConcurrent from second thread.
I am running a programme that has multithreading . The programme firstly has a main / UI thread running in it. In this programme I have a worker and handler class.
The worker class is having a simulate function which simply generates the random number. The simulate function continuously generates the number without blocking any thread i.e. via Qtconcurrent.
From the main/UI thread I have put this worker class into new thread. The handler class is running in main /UI thread and is responsible to communicate with worker class running in other thread via signal slot.
So far everything is ok.
Problem starts when i try to close the programme by simply clicking on app cross button. The programme sort of hangs it does not close. However when i dont put worker in another class . The Same codes work and programme exits with 0.
So my question is how to stop Qtconcurrent is another thread and finally close the another thread aswell.
Thank You.
main.cpp
int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); QQmlApplicationEngine engine; QThread l_newThread; Worker* l_worker = new Worker(); handler * l_handler = new handler(); l_worker->moveToThread(&l_newThread); QObject::connect(&l_newThread, &QThread::started, l_worker, &Worker::Init); QObject::connect(l_handler,&handler::toStop_Signal,&l_newThread, &QThread::quit); QObject::connect(l_worker, &Worker::toStop_Signal_Worker, l_handler,&handler::toStop_Slot); QObject::connect(&app,&QCoreApplication::aboutToQuit, l_worker, &Worker::stop); // QObject::connect(&app,&QCoreApplication::aboutToQuit, &l_newThread, &QThread::quit); l_newThread.start(); // l_worker->Init(); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); if (engine.rootObjects().isEmpty()) return -1; int result = app.exec(); l_newThread.wait(); return result; }
handler #include "handler.h" handler::handler(QObject *parent) : QObject(parent) { } void handler::toStop_Slot() { emit toStop_Signal(); }
worker.cpp
#include "worker.h" Worker::Worker(QObject *parent) : QObject(parent) { } void Worker:: Init() { m_simulation = true; simulate(); } void Worker::simulate() { QtConcurrent::run([this]{ QRandomGenerator generator; while (m_simulation) { qint32 t = generator.bounded(0,100); qDebug() << t; qDebug() << "sleeping for 1 second"; QThread::sleep(1); } if (!m_simulation) { qDebug() << "Killing the concurrent thread"; // QThread::currentThread()->exit(); emit toStop_Signal_Worker(); } }); } void Worker::stop() { m_simulation = false; }
results
QML debugging is enabled. Only use this in a safe environment. 19 sleeping for 1 second 55 sleeping for 1 second 70 sleeping for 1 second 69 sleeping for 1 second Killing the concurrent thread
-
Hi,
you are doing a thread in a thread...
QtConcurrent::run creates a thread for you, no needance for putting the worker object into another thread.You can do it like this:
class Worker : public QObject{ bool m_simulation; public: QFuture<void> future; Worker(QObject *parent=0); void Init(); void simulate(); void stop(); }; Worker::Worker(QObject *parent) : QObject(parent){} void Worker::Init() { m_simulation = true; simulate(); } void Worker::simulate() { future = QtConcurrent::run([this] { QRandomGenerator generator; while (m_simulation) { qint32 t = generator.bounded(0, 100); qDebug() << t; qDebug() << "sleeping for 1 second"; QThread::sleep(1); } if (!m_simulation) { qDebug() << "Killing the concurrent thread"; // QThread::currentThread()->exit(); //emit toStop_Signal_Worker(); } }); } void Worker::stop() { m_simulation = false; }
and then in your main:
Worker *l_worker = new Worker(); l_worker->Init(); QObject::connect(&a, &QCoreApplication::aboutToQuit, l_worker, &Worker::stop); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); if (engine.rootObjects().isEmpty()) return -1; int result = app.exec(); l_worker->future.waitForFinished();
-
@Gerd Thank You. I know running it directly wont be a problem as you illustrated in your example.
I have also mentioned this in my first post. "The programme sort of hangs it does not close. However when i dont put worker in another class . The Same codes work and programme exits with 0."
This example/ question is a part of bigger programme. The basic Idea of this example is to know how to stop programme when programme is having an additional thread and qtconcurrent is running in that. Then how to stop the programme.
-
Does QThread::sleep process events?
If not you need to process events in your thread. Try putting doing this:... QCoreApplication::processEvents(); QThread::sleep(1);
-
@Mandeep-Chaudhary Can you explain why you're using QtConcurrent::run() in a thread? What is the point? You're already in your second thread, why creating a third one from the second?
-
@jsulm Thank you for your reply. Question here is not "What is the point? You're already in your second thread, why creating a third one from the second?" and so on.
Question is very simple as QtConcurrent::run() is executed from second thread which is working (as shown above) then
how to stop it. We can discuss the philoshopical things at later stage. First its important to utilize all possibilities in QT. -
@fcarney Thank You for your reply. I am afraid I did not understand what you mean by "you need to process events in your thread". If I assume you mean to say something similar as mentioned in the first reply then for sure we are going of the topic.
-
@Mandeep-Chaudhary
QtConCurrent::run, returns a QFuture, store this in a member variable and on worker destruction, check if the QFuture is still valid and running.
If it is, callcancel()
followed bywaitForFinished()
-
even if i think thats not usefull....
QThread l_newThread; Worker *l_worker = new Worker(); l_worker->moveToThread(&l_newThread); l_newThread.start(); l_worker->Init(); QObject::connect(&a, &QCoreApplication::aboutToQuit, l_worker, &Worker::stop); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); if (engine.rootObjects().isEmpty()) return -1; int result = app.exec(); l_worker->future.waitForFinished(); l_newThread.quit();
-
@J-Hilk and @Gerd Thank You for your replies. I combined your logic with handler and now it works.
Basically now programme makes sure first qtconcurrent is stopped and then the second thread.
int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); QQmlApplicationEngine engine; QThread l_newThread; Worker* l_worker = new Worker(); handler * l_handler = new handler(); l_worker->moveToThread(&l_newThread); QObject::connect(&l_newThread, &QThread::started, l_worker, &Worker::Init); QObject::connect(l_handler,&handler::toStop_Signal,l_worker, &Worker::stop); QObject::connect(&app,&QCoreApplication::aboutToQuit, l_handler,&handler::toStop_Slot); l_newThread.start(); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); if (engine.rootObjects().isEmpty()) return -1; int result = app.exec(); l_worker->future.waitForFinished(); l_newThread.quit(); l_newThread.wait(); return result; }