QThreads never quit although emit Finished reached - c++

Following scenario:
If the user press the "StartMeasure" button I start a new worker thread to avoid blocking behaviour in GUI!
There I start again n new threads for hardware communication (need parallel flow for reasons of speed) -> send/receive something and evaluate the response.
Thread model:
The problem is that the n worker threads (for HW communication) never quits!
Simplified code:
void Tool::on_btn_StartMeasure()
{
TestExecution *testExecution = new TestExecution();
QThread *workerThread = new QThread();
connect(workerThread, &QThread::started, testExecution, &TestExecution::DoTest);
connect(testExecution, &TestExecution::Finished, workerThread, &QThread::quit);
testExecution->moveToThread(workerThread);
workerThread->start();
}
TestExecution Class
class TestExecution : public QObject
{
Q_OBJECT
public:
void DoTest();
signals:
void Finished();
};
void TestExecution::DoTest()
{
std::vector<std::shared_ptr<TestFlow>> objects;
std::vector<QThreads*> workerThreads;
for(int n=0; n<numberOfDevices; n++)
{
workerThreads.push_back(new QThread());
objects.push_back(std::make_shared<TestFlow>());
connect(workerThreads.back(), &QThread::started, objects.back().get(), &TestFlow::DoWork);
connect(objects.back().get(), &TestFlow::Finished, workerThreads.back(), &QThread::quit);
objects.back()->moveToThread(workerThreads.back());
workerThreads.back()->start;
}
// wait for worker threads to finish
for(auto it=workerThreads.begin(); it!=workerThreads.end(); it++)
{
(*it)->wait(30); // wait a maximum of 30s -> for testing
}
// do something with the result <--- NEVER REACHED
emit Finished();
}
TestFlow Class
class TestFlow : public QObject
{
Q_OBJECT
public:
void DoWork();
signals:
void Finished();
};
void TestFlow::DoWork()
{
// do something
emit Finished(); <-- REACHED
}
If I reach the Finished signal in TestFlow he steps into qobject_impl.h to the method QSlotObjectBase::call(Object *r, void **a) and stops there. If I wait long enough (thread timeout of 30s) the workerThreads terminates!
Something wrong or missing here?
Thank you for any help!
UPDATE:
output of qDebug (only 1 worker thread)
Tool::on_btn_StartMeasure(), currentThread QThread(0x601b08), object thread QThread(0x601b08)
TestExecution::DoTest(), currentThread QThread(0x388bf68) , object thread QThread(0x388bf68)
TestFlow::DoWork(), currentThread QThread(0x3958690) , object thread QThread(0x3958690)
Looks ok to me?!

Related

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.

QThread: Destroyed while thread is still running and QMutex destroyed

I am trying to add multiple threads to my Qt application but right when it executes this thread the program just crashes and i get an error of
QThread: Destroyed while thread is still running
QMutex: destroying locked mutex
I understand the error message i just dont know how i can fix it. My code is below.
Header
class Worker : public QObject
{
Q_OBJECT
private slots:
void onTimeout()
{
qDebug()<<"Worker::onTimeout get called from?: "<<QThread::currentThreadId();
}
};
class Thread : public QThread
{
Q_OBJECT
private:
void run()
{
qDebug()<<"From work thread: "<<currentThreadId();
QTimer timer;
Worker worker;
connect(&timer, SIGNAL(timeout()), &worker, SLOT(onTimeout()));
timer.start(1000);
exec();
}
};
login.cpp
void Login::on_pushButton_clicked()
{
QSqlQuery query;
QString Username = ui->Username_lineEdit->text();
QString Password = ui->Password_lineEdit->text();
query.prepare("SELECT * FROM Program_account WHERE Login = '"+ Username +"' AND Password = '"+ Password +"'");
if(!query.exec())
{
qDebug() << "SQL QUERY Login:" << query.executedQuery();
qDebug() << "SQL ERROR Login:" << query.lastError();
}
else if(!query.first())
{
tries++;
int x = 10 - tries;
ui->label->setText("Incorrect Username or Password " + QString::number(x) + " tries until timeout");
}
else
{
QSqlQuery Account_Type_Query("SELECT Account_Type FROM Program_account WHERE Login = '"+ Username +"' AND Password = '"+ Password +"'");
while(Account_Type_Query.next())
{
Account_Type = Account_Type_Query.value(0).toInt();
}
tries = 0;
static Home *home = new Home;
home->show();
close();
}
if(tries == 10)
{
Thread t;
t.start();
ui->label->setText("Password entered wrong too many times, entered 10 minute cooldown period");
ui->pushButton->hide();
QTimer::singleShot(600000, ui->pushButton, SLOT(show()));
tries = 0;
ui->label->setText("");
}
What is the correct way i can fix this issue. All help is much appreciated.
Thank you
Update:
Tried
class Thread : public QThread
{
Q_OBJECT
private:
void run()
{
while(QThread::wait())
{
qDebug()<<"From work thread: "<<currentThreadId();
QTimer timer;
Worker worker;
connect(&timer, SIGNAL(timeout()), &worker, SLOT(onTimeout()));
timer.start(1000);
exec();
}
QThread::quit();
}
};
but still receiving the same error
Inheriting from QThread is one issue here and I suspect that the Worker object does not have the thread affinity you think it has and is running on the main thread.
The reason for the crash is that you create your Thread instance on the stack,
if(tries == 10)
{
Thread t; // NOTE THIS IS ON THE STACK
t.start();
ui->label->setText("Password entered wrong too many times, entered 10 minute cooldown period");
ui->pushButton->hide();
QTimer::singleShot(600000, ui->pushButton, SLOT(show()));
tries = 0;
ui->label->setText("");
}
The Thread instance is being destroyed when it goes out of scope.
Regardless, I strongly suggest following the advice of #Thomas and adhere to the way in which Maya uses threads, without the need for inheriting QThread.

Qt: Is QHttp's get function thread safe?

I have the following code:
class USBCamCaptureThread : public QThread
{
Q_OBJECT
void run() {
while (!threadQuit){
mutex.lock();
bytes.clear();
buffer->reset();
Request = http->get (url->path(),buffer););
mutex.unlock();
MG::SLEEP::msleep(250);
}
}
public:
USBCamCaptureThread(){
QFile file("setting_files/cameraIP.txt");
QString line = "192.168.1.5:80"; //default value
if(file.open(QIODevice::ReadOnly)) {
QTextStream in(&file);
line = in.readLine();
}
file.close();
url = new QUrl(line);
http = new QHttp(this);
buffer = new QBuffer(&bytes);
threadQuit = false;
imageReaded = true;
open(0);
}
~USBCamCaptureThread(){
}
public slots:
void Finished(int requestId, bool error){
QImage localImage;
mutex.lock();
localImage.loadFromData(bytes);
mutex.unlock();
QImg = localImage;
emit signalUSBImageRead();
}
bool open(int camID){
buffer->open(QIODevice::WriteOnly);
http->setHost(url->host());
connect(http, SIGNAL(requestFinished(int, bool)),this, SLOT(Finished(int, bool)));
return true;
}
Note that the run() is in a worker thread and the Finished() is in the main thread.
My question is: since the documentation says the QHttp get function is "The function does not block; instead, it returns immediately. The request is scheduled, and its execution is performed asynchronously."
Is it possible that when the requestFinished is emitted and Finished() is triggered, it happens that the run() function has the mutex and therefore the QBytearray bytes.clear() is called and when Finished() got the mutex, there is nothing to be loaded from the QBytearray bytes?
Furthermore, if the process of http->get() is scheduled to be processed later, does that mean its operation on buffer is no longer protected by the mutex?

Interesting task of the processes in Qt

Suppose I run a console application using QProcess. The application runs, displays some information, and then waits for n seconds and displays other information.
My current code is:
QProcess * p = new QProcess();
p->start("test.bat");
p->waitForStarted();
p->waitForFinished();
p->readAll();
delete p;
Currently I get all the output at the end, but what I need to do is get the output and display it as it becomes available. How do I do this?
You could connect to the readyRead() signal, so whenever there is some data to read, you will keep reading it and display without waiting for the process to finish. That means the following in terms of code:
class Foo : public QObject
{
Q_OBJECT
public:
explicit Foo::Foo(QObject parent = Q_NULLPTR)
: QObject(parent)
{
...
connect(myProcess, SIGNAL(readyRead()), SLOT(handleReadyRead()));
connect(myProcess, SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(handleFinished(int, QProcess::ExitStatus)));
connect(myProcess, SIGNAL(error(QProcess::ProcessError)), SLOT(handleError(QProcess::ProcessError)));
myProcess.start("test.bat");
...
}
public slots:
void Foo::handleReadyRead()
{
qDebug() << myProcess.readAll();
}
void Foo::handleFinished(int, QProcess::ExitStatus)
{
// Handle finished
}
void Foo::handleError(QProcess::ProcessError)
{
// Handle error
}
private:
QProcess myProcess;
}
Disclaimer: consider it as pseudo-code as I have not built it, but it should demonstrate the concept to use.

I just don't understand threads in Qt

Okay, so, here's the deal.
I'm currently writing a small chat messaging simulation / project using SysV IPC, and I use Qt for my client app. What I want is a background thread that would wait on a message queue and send a signal to a GUI thread whenever a new message comes. I have attempted to write the code using QThread inheritance, but it doesn't seem to work, the messages are not shown, and I think I'm missing something here.
As for the code:
ipcEventListener.h:
class IPCEventListener : public QThread
{
Q_OBJECT
public:
IPCEventListener();
void run();
messageWrapper mw;
signals:
void sendChatMsg(MSG_CHAT_MESSAGE cm);
};
ipcEventListener.cpp
IPCEventListener::IPCEventListener()
{
}
void IPCEventListener::run()
{
mutex.lock();
int n = msgrcv(myQueueId, &mw, sizeof(mw)-sizeof(long), 0, IPC_NOWAIT);
mutex.unlock();
if (n>0)
{
snip...
else if (mw.resp.type == MESSAGE)
{
emit sendChatMsg(mw.chatMsg);
}
}
exec();
}
mainwindow.cpp:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
listener = new IPCEventListener(this);
connect(this->listener, SIGNAL(sendChatMsg(MSG_CHAT_MESSAGE)), this, SLOT(message_received(MSG_CHAT_MESSAGE)));
connect(this->ui->pushButton, SIGNAL(clicked()), this, SLOT(on_pushButton_clicked()));
listener->start();
ui->comboBox->addItem("Client");
ui->comboBox->addItem("Room");
}
void MainWindow::message_received(MSG_CHAT_MESSAGE cm)
{
QString formattedMessage = "";
formattedMessage.append("[");
formattedMessage.append(cm.send_time);
formattedMessage.append("] ");
if (cm.msg_type == PRIVATE) formattedMessage.append("[PRIV:] ");
formattedMessage.append(cm.sender);
formattedMessage.append(": ");
formattedMessage.append(cm.message);
formattedMessage.append("\n");
ui->textEdit->append(formattedMessage);
}
What am I missing?
(PS: I know the code probably breaks about a hundred thousand of code conventions, but the deadline is pretty soon and I have to resort to kludges. It's just a school project, though).
You have a logical error in your code. You treat void IPCEventListener::run() as a method which is in a loop and is executing again ang again ang again but it's not. QThread::run() is method where you only initialize your thread and execute exec() function, to start event loop. It means that in current version of your application, you try to receive message just once and then your thread is just waiting for some events, without doing anything with them.
So what you need is an inifite loop in which you will try to receive messages. And don't forget to stop this loop while program closing.