Qt, C++, How to Quit QThread - c++

I have a calculator and a calculator method startCalculations() which is to put onto a QThread. I successfully connect mStopCalcButton and the thread's quit()/terminate(). However, when I press mStopCalcButton, the thread does not quit/terminate.
Here is the code in question...
mStopCalcButton->setEnabled(true);
QThread* thread = new QThread;
Calculator* calculator = new Calculator();
calculator->moveToThread(thread);
connect(thread, SIGNAL(started()), calculator, SLOT(startCalculations())); //when thread starts, call startCalcuations
connect(calculator, SIGNAL(finished()), thread, SLOT(quit()));
connect(calculator, SIGNAL(finished()), calculator, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
connect(mStopCalcButton, SIGNAL(released()), thread, SLOT(quit()) );
In the calculator, this is the only defined method...
void Calculator::startCalcuations()
{
int x = 0;
while (true)
qDebug() << x++;
}
Why does my QThread not quit?

The first thing, function QThread::quit() only tell that thread to exit it's event loop, but do nothing related to terminate or exit. you can read Qt document here: QThread:quit()
To terminate a thread, in general implement, you should change your thread's running function code by using stop flag rather than infinitive loop. Whenever you want to terminate thread, you only need change that stop flag and wait for thread terminating.
Using stop flag:
void Calculator::startCalcuations()
{
int x = 0;
while (!mStopFlag) {
qDebug() << x++;
// In addition, you should add a little sleep here to avoid CPU overhelming
// like as msleep(100);
}
}
Terminate thread by turning on the stop flag:
void YourClass::requestTerminateThread()
{
mStopFlag = true;
if(!thread.wait(500))
{
thread.terminate(); // tell OS to terminate thread
thread.wait(); // because thread may not be immediately terminated by OS policies
}
}
In addition, as you can see my comment on above code, you should add some thread sleep time to avoid CPU overhelming.
For more information, please clearly read QThread document specs first.

Related

How to start a loop on a QThread

How can I start a loop on a different thread by pressing a QPushButton?
The main idea is, when pushButtonStart is clicked, start a loop on a QThread, and when pushButtonStop is clicked, stops the loop in the QThread.
The loop can be done by QTimer, for loop or while loop, but he needs a way to stop by pressing a button.
I have this code to create a new timer and set up a connection when it fires. This is in the Start code.
checkTimer = new QTimer(this);
connect( checkTimer, SIGNAL(timeout()), this, SLOT(checkTimerFired()) );
checkTimer->start(3000);
My "stop running" button sets programCreated to false, and checkTimerFired starts with this:
if (!programCreated) {
checkTimer->stop();
return;
}
That should be the Qt-specific things you need. The rest is simple C++.
To do the loop, I use QTimer, which run the slot pressButton multiple times until stop(); function of QTimer is executed. Of course, to use this method I have to recode the program, to improve the algorithm.
QTimer loop:
void MainPrograma::on_pushTurnOn_clicked()
{
tierLoop = new QTimer(this);
timerLoop->setInterval(5000);
timerLoop->setSingleShot(true);
connect(timerLoop, SIGNAL(timeout()), SLOT(on_pushTurnOn_clicked()));
QPushButton *ThirdButton = uimain->QPushButton_3;
Nmb2 = 2
Nmb4 = 4;
if(Busy==1){
ThirdButton->setEnabled(false);
}
if(Busy==0){
timerLoop->start(); //start the loop
StartFunction(Nmb2, Nmb4);
if(X==1){
ThirdButton->setEnabled(false);
}
if(X==0){
ThirdButton->setEnabled(true);
}
}
}
void MainPrograma::on_pushTurnOff_clicked()
{
timerLoop->stop(); //stop the loop
}
QTimer declaration on .h:
private:
QTimer *timerLoop;
I still do not understand how to use QThread... But the loop is already answered!

How to close the programme when running a qtconcurrent from another thread in qt

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 and run worker class from same main /UI thread then there is no problem 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;
}
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;
}
handler.cpp
#include "handler.h"
handler::handler(QObject *parent) : QObject(parent)
{
}
void handler::toStop_Slot()
{
emit toStop_Signal();
}
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
What probably happens here: the signal toStop_Signal which is meant to quit l_newThread is never delivered, because when it's emitted the event loop is already dead and gone. Hence, your program is stuck waiting for the thread in l_newThread.wait();.
I don't fully get why you start this thread at all, just to use QtConcurrent::run right after and span yet another thread ...
Anyway, once you're sure your worker has stopped (and you are, according to the output you posted), you can safely quit the (basically useless) thread directly in your main:
int result = app.exec();
l_newThread.exit(); //just quit it
l_newThread.wait();
return result;
Then you can get rid of this connection:
QObject::connect(l_handler,&handler::toStop_Signal,&l_newThread, &QThread::quit);
and (I guess) of the handler altogether.

Passing classes to worker in QThread

I'm developing an application which parses a list of binary files and saves the results into a database. The processing of the files takes a rather long time. Therefore I'm showing the user a progress bar and a list of processed files. When a file is successfully processed, I want to update the processbar. If the user aborts the processing (i.e. clicks on the window's 'x' -> &ParseAssistant::rejected), I need to kill the thread and delete the allocated objects (i.e. PluginWorker* and QThread*).
/* mainwindow.cpp */
ParseAssistant parseWindow(files.size());
QThread* thread = new QThread();
PluginWorker* worker = new PluginWorker(pluginConnector, pluginProcessor, files);
worker->moveToThread(thread);
// Update GUI (progressbar + filelist)
connect(worker, &PluginWorker::updateProgress, &parseWindow, &ParseAssistant::updateProgress);
connect(thread, SIGNAL (started()), worker, SLOT (process()));
connect(worker, SIGNAL (finished()), thread, SLOT (quit()));
connect(thread, SIGNAL (finished()), thread, SLOT (deleteLater()));
connect(worker, SIGNAL (finished()), worker, SLOT (deleteLater()));
// Stop PluginWorker on 'x'-click
connect(&parseWindow, &ParseAssistant::rejected, worker, &PluginWorker::stop);
connect(worker, &PluginWorker::finished, &parseWindow, &ParseAssistant::parsingFinished);
thread->start();
parseWindow.exec();
First, I'm creating a QDialog (ParseAssistant) which contains the progressbar and the list of processed files. Afterwards I create a Worker-Thread-pair and bind them as described in 'How To Really, Truly Use QThreads'. The 'pluginConnector' has access to the plugin an parses the files; the pluginProcessor writes the results to a database.
/* pluginworker.cpp */
PluginWorker::PluginWorker(PluginConnector& pc, PluginProcessor& processor, QStringList list)
{
connect(this, SIGNAL(parseNext(int)), this, SLOT(process(int)));
}
// Called on 'x'-press
void PluginWorker::stop()
{
isStopped = true;
}
void PluginWorker::process(int idx)
{
if (isStopped) {
emit finished();
return;
}
if (0 <= idx && idx < files.length()) {
/*
* Parse file using PluginConnector and
* use result with PluginProcessor
*/
emit updateProgress(idx+1, error, source);
emit parseNext(idx+1);
} else {
emit finished();
}
}
I use signals/slots to call parseNext, because this allows Qt to call stop() (when &ParseAssistant::rejected signal is received). An alternative would be to iterate over the files and call QCoreApplication::processEvents to process signals.
This construct mostly works, but crashes when I abort the process using the 'x'. I can't track down exactly what crashes the application, but I'm fairly certain that my approach is flawed, because the 'worker' and the 'pluginConnector/pluginProcessor' live in different threads, but I don't know how to correctly use this.

How do I wait for a thread to finish in Qt without blocking its execution?

I have a function that creates a bunch of QThreads to speed up a long calculation, but when I try and sleep until the calculation is done, the background threads never execute for some reason.
I can't figure out why the threads don't execute after I call thread->start(). Here's my code:
multithread.run_multithread(run_function, thread_count);
while(multithread.running)
QThread::msleep(100);
qDebug() << "done"; // Never reaches this point
And the multithread function:
void Multithread::run_multithread(std::function<void
(int)>run_function_in, int thread_count) {
running = true;
// Create workers and threads
int thread_idx;
for(thread_idx=0; thread_idx<thread_count; thread_idx++) {
ThreadWorker *worker = new ThreadWorker(this, run_function_in);
QThread *thread = new QThread();
// Set workers and threads to delete when done
worker->moveToThread(thread);
connect(worker, &ThreadWorker::finished, this, &Multithread::check_progress);
connect(thread, &QThread::started, worker, &ThreadWorker::run);
connect(worker, &ThreadWorker::finished, thread, &QThread::quit);
connect(worker, &ThreadWorker::finished, worker, &ThreadWorker::deleteLater);
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
// Start thread
thread->start();
}
}
running gets set to false in Multithread::check_progress when all the threads finish their part of the calculation. When I remove QThread::msleep(100) the calculation will execute normally, but I need some way to block until it completes.
Rather than using QThread, I would recommend using the Qt Concurrent functionality which provides a higher level of abstraction over the thread primitives. You can use QFutureSynchronizer to wait for several concurrent futures to finish. This object will wait for all attached futures to finish before it allows itself to be destroyed.
An example of how to start several threads and then wait for them all to finish is:
#include <QtConcurrent>
void run_multithread(...) {
// Set up a new synchronizer.
QFutureSynchronizer<void> synchronizer;
// Run n tasks in parallel.
for (int thread_idx = 0; thread_idx < thread_count; ++thread_idx) {
synchronizer.addFuture(QtConcurrent::run(run_function_in));
}
// The synchroniser will wait for all threads to finish before returning.
}
It could be because of optimization, since multithread.running is not changed inside the loop. However, here the main reproducible reason is that the slot Multithread::check_progress is never called by ThreadWorker::finished signals, since the instance of Multithread belongs to your current thread, but the event loop is blocked.
Instead of such sleep you can emit a signal from Multithread object when all threads are finished. Then the computation may be continued from a slot connected to that signal.

Qt emitted signal form a background thread to the main thread never arrives

I have difficulties to get a Qt::QueuedConnection between a background thread and my main application running. I have a camera capturing class derived from QObject which is moved to a QThread by using:
m_CameraCapture.moveToThread(&m_CameraCaptureThread);
Afterwards, I connect the signals and slots:
//Connect error signal)
QObject::connect(&m_CameraCapture, SIGNAL(error(QString,QString)), this, SLOT(reportError(QString,QString)));
//Connect the finished signal of the worker class to the thread for quitting the loop
connect(&m_CameraCapture, SIGNAL(finished()), &m_CameraCaptureThread, SLOT(quit()));
//This connections guarantees that the *m_CVideoCapture is automatically deleted if the event loop of the thread is terminated. Therefore, m_CVideoCapture does not need to be released manually if the capturing process is stopped.
QObject::connect(&m_CameraCaptureThread, SIGNAL(finished()), &m_CameraCaptureThread, SLOT(deleteLater()));
QObject::connect(&m_CameraCapture, SIGNAL(finished()), &m_CameraCapture, SLOT(deleteLater()));
//Connect sendFrame to update frame for displaying the current frame
QObject::connect(&m_CameraCapture, SIGNAL(sendFrame(cv::Mat)), this, SLOT(receiveFrame(cv::Mat)),Qt::BlockingQueuedConnection);
QObject::connect(this, SIGNAL(startGrabbing()), &m_CameraCapture, SLOT(startGrabbing()));
QObject::connect(this, SIGNAL(stopGrabbing()), &m_CameraCapture, SLOT(stopGrabbing()));
The m_CameraCapture object contains a timer which calls in regular intervals the grabFrame() slot of m_CameraCapture. The function is defined by:
void CCameraCapture::grabFrame(){
QMutexLocker ml(&m_Mutex);
qDebug() << "Elapsed time " << GetTickCount()-lastTickCount<<" ms";
qDebug() << "Thread ID timer: " << m_Timer.thread();
qDebug() << "Thread ID worker: " << this->thread();
lastTickCount=GetTickCount();
//Local image storage
cv::Mat cvFrameBGR;
//Get new frame from camera
m_Cap>>cvFrameBGR;
//cv::Mat cvFrameRGB;
////Convert frame to RGB
//cv::cvtColor(cvFrameBGR, cvFrameRGB, CV_BGR2RGB);
////Convert cv::Mat to QImage
//m_Frame=QImage((uchar*)(cvFrameRGB.data),cvFrameRGB.cols,cvFrameRGB.rows,QImage::Format_RGB888);
//Send frame to receivers
emit sendFrame(cvFrameBGR);
}
The thread IDs of timer and thread are the same and different to the thread ID of the main application - so this seems to be correct. The point is the line
emit sendFrame(cvFrameBGR);
This signal only arrives at the main application if I use
QObject::connect(&m_CameraCapture, SIGNAL(sendFrame(cv::Mat)), this, SLOT(receiveFrame(cv::Mat)),Qt::BlockingQueuedConnection);
in the main application to connect it. But this is not what I want because it will slow down my capturing loop. I would like to connect it with a Qt::QueuedConnection. However, when I use a QueuedConnection instead of the BlockingQueuedConnection the receiveFrame(cv::Mat) slot in the receiving Object is never executed (Also with AutoConnection it wont work). The receiving Object is a cameraHandler class which is derived from QObject. Thanks for any hint!