Not getting display in UI in QThread
-
I am trying to create a pipelining architecture with QThread with 3 threads
1.Capture
2.Process
3.DisplayMy display thread is not working.Please help me to find my bug.
Here is my code snnippet
capture.h
#ifndef CAPTURE_H #define CAPTURE_H #include <QObject> namespace Ui { class Capture; } class Capture : public QObject { Q_OBJECT public: explicit Capture(QObject *parent = nullptr); signals: void inputAvailable(int i); public slots: void startCapture(); }; #endif // CAPTURE_H
capture.cpp
#include "capture.h" #include <QMutex> #include <QThread> static int check = 0; Capture::Capture(QObject *parent) : QObject(parent) { } void Capture::startCapture() { //for(int i = 0; i <= 100; i++) while(1) { int i = check; QMutex mutex; // prevent other threads from changing the "Stop" value mutex.lock(); mutex.unlock(); // emit the signal for the count label emit inputAvailable(i); check++; // slowdown the count change, msec QThread::msleep(500); } }
process.h
#ifndef PROCESS_H #define PROCESS_H #include <QObject> namespace Ui { class Process; } class Process: public QObject { Q_OBJECT public: explicit Process(QObject *parent = nullptr); signals: // To communicate with Gui Thread // we need to emit a signal void valueChanged(int); public slots: void inputHandler(int i); }; #endif // PROCESS_H
process.cpp
#include "process.h" #include <QThread> #include <QDebug> Process::Process(QObject *parent) : QObject(parent) { } void Process ::inputHandler(int i) { qDebug()<<"Process thread"<<QThread::currentThreadId(); i = i+100; emit valueChanged(i); qDebug()<<"Randomized"; }
display.h
#ifndef DIALOG_H #define DIALOG_H #include <QDialog> #include <QString> #include "mythread.h" namespace Ui { class dialog; } class dialog : public QDialog { Q_OBJECT public: explicit dialog(QWidget *parent = 0); ~dialog(); MyThread *mThread; private: Ui::dialog *ui; public slots: void onValueChanged(int); private slots: // for Start button void on_pushButton_clicked(); // for Stop button void on_pushButton_2_clicked(); }; #endif // DIALOG_H
display.cpp
#include "dialog.h" #include "ui_dialog.h" #include "mythread.h" #include "process.h" #include "capture.h" #include <QDebug> dialog::dialog(QWidget *parent) : QDialog(parent), ui(new Ui::dialog) { ui->setupUi(this); } dialog::~dialog() { delete ui; } // Absorb the signal emitted from a run() method // and reflect the count change to the count label // in our dialog void dialog::onValueChanged(int count) { qDebug()<<"On Value changed"; ui->label->setText(QString::number(count)); } // Start button void dialog::on_pushButton_clicked() { QThread capture_qthread,process_qthread; capture_qthread.start(); process_qthread.start(); Capture capture_thread; Process process_thread; dialog display_thread; capture_thread.moveToThread(&capture_qthread); process_thread.moveToThread(&process_qthread); //display_thread.moveToThread(&display_qthread); QObject::connect(&capture_thread,&Capture::inputAvailable, &process_thread,&Process::inputHandler); QObject::connect(&process_thread, &Process::valueChanged, &display_thread, &dialog::onValueChanged); capture_thread.startCapture(); } // Stop button void dialog::on_pushButton_2_clicked() { mThread->Stop = true; }
-
@DhivyaJR said in Not getting display in UI in QThread:
void dialog::on_pushButton_clicked()
{QThread capture_qthread,process_qthread;
c++ basics - how long do these objects live?
-
@DhivyaJR said in Not getting display in UI in QThread:
My display thread is not working.Please help me to find my bug.
In what way "not working"? It would help if you stated what is going wrong.
I am a thread-virgin, so these are just some observations which may or may not help.....
-
You don't do anything with
dialog display_thread;
, and it's a local variable anyway. -
As I say, I am not an expert, but your
Capture capture_thread
&Process process_thread
are also local variables. They go out of scope at the end ofon_pushButton_clicked()
. I don't know what happens to them when you have moved them to another thread, given that you have passed pointers to stack variables? -
I take it you know that, at least as written, the
QMutex mutex
does nothing?
-
-
@Christian-Ehrlicher
Thread will start if start button is clicked and stopped when stop button pressed -
@DhivyaJR
Hi
As @Christian Ehrliche and @JonB say you are using local objects but more display_thread seems to be not useful for you.I think you must change the second connect in
QObject::connect(process_thread, &Process::valueChanged, this, &dialog::onValueChanged);
process_thread used as pointer and not as local object
-
@JonB '
my output as follows17:54:30: Starting /home/dhivyajr/build-qThreadDisplay_learining-Desktop_Qt_5_15_2_GCC_64bit-Debug/qThreadDisplay_learining ... Process thread 0x7f32ce059700 Randomized Process thread 0x7f32ce059700 Randomized Process thread 0x7f32ce059700 Randomized Process thread 0x7f32ce059700 Randomized Process thread 0x7f32ce059700 Randomized Process thread 0x7f32ce059700 Randomized Process thread 0x7f32ce059700 Randomized Process thread 0x7f32ce059700 Randomized Process thread 0x7f32ce059700 Randomized Process thread 0x7f32ce059700 Randomized Process thread 0x7f32ce059700 Randomized
It should enter display_thread and print this message
"On Value changed". But not printing -
@DhivyaJR said in Not getting display in UI in QThread:
Thread will start if start button is clicked and stopped when stop button pressed
But it's still a local variable which gets destroyed after the function finishes...
-
Threads is a complicated topic. The main problem you have (besides the ones others have mentioned) is that
capture_thread.startCapture()
will be executed in the "display thread". This is just calling a function and normal function call will execute in the calling thread. In order to execute the slot inside the other thread you need to invoke the method through the event loop of the other thread.As I said, threads are complicated. I will try my best to rewrite your function out of the top of my head (untested):
void dialog::on_pushButton_clicked() { // threads with non-local lifetime => should make these member variables! QThread *capture_qthread = new QThread(); QThread *process_qthread = new QThread(); capture_qthread.start(); process_qthread.start(); // these objects also need to live longer => best to make these member variables as well Capture *capture_thread = new Capture(); Process *process_thread = new Process(); // dialog display_thread; // <-- Don't do this. This creates a new object (with local lifetime) which is not the same as 'this'. capture_thread.moveToThread(capture_qthread); process_thread.moveToThread(process_qthread); //display_thread.moveToThread(&display_qthread); QObject::connect(capture_thread,&Capture::inputAvailable, process_thread,&Process::inputHandler); QObject::connect(process_thread, &Process::valueChanged, this, &dialog::onValueChanged); QMetaObject::invokeMethod(capture_thread, "startCapture"); }
This code needs further changes as now you have to manage the lifetime of your objects explicitely (which is not done in the code sample I gave). Note that objects are deleted in the context of their respective threads (or rather: have to be deleted in the context of their respective threads. Call
deleteLater
oncapture_thread
andprocess_thread
before deleting their respective threads. For the threads it is best to connect finished to deleteLater:connect(capture_qthread, &QThread::finished, capture_qthread, &QThread::deleteLater)
and then callquit()
on them. -
@Christian-Ehrlicher said in Not getting display in UI in QThread:
But it's still a local variable which gets destroyed after the function finishes...
The function will never finish because it is still running an infinite loop inside
startCapture()
:=). Also it is blocking the event loop of the display thread... -
@SimonSchroeder said in Not getting display in UI in QThread:
capture_thread.moveToThread(capture_qthread);
process_thread.moveToThread(process_qthread);Don't do that ! That's a bad anti pattern.Watch out for the moveToThread anti-pattern when using so close variable names. See here and here.
[edit: missed the single q between the variable names SGaist]
-
@DhivyaJR said in Not getting display in UI in QThread:
1.Capture
2.Process
3.Display
My display thread is not working.Please help me to find my bug.First, Qt is an asynchronous framework. There is no good reason the lock the thread with active wait, even more when it is the main thread.
To made signals/slots works, the thread event loop must be called.
But as you have a while(1) loop inCapture::startCapture()
, this will lock the acces to the event loop... So no signal/slot can be process for this thread.Second, are you sure that you need to create a thread?
There are many alternatives in Qt framework, like QtConcurrent::run() to simplify processing data in another thread.
In conbination with QFutureWatcher to be informed about processing end, this could simplify your code. -
@SGaist said in Not getting display in UI in QThread:
Don't do that ! That's a bad anti pattern. See here and here.
These two articles warn against using this->moveToThread(this). And also they are talking about using moveToThread inside classes that derive from QThread. Neither is there any class derived from QThread nor is moveToThread called on
this
. The first link also says that it is still necessary to call moveToThread on your objects...I would personally do the design differently, but didn't want to rewrite the whole code. Keeping with the design this is a proper solution. (@KroMignon correctly started a debate if the design is correct.) Also it teaches a little bit how QThread works, how C++ works (object lifetime), and the dangers/pitfalls of using QThread explicitely.
-
@SGaist said in Not getting display in UI in QThread:
@SimonSchroeder said in Not getting display in UI in QThread:
capture_thread.moveToThread(capture_qthread);
process_thread.moveToThread(process_qthread);Don't do that ! That's a bad anti pattern. See here and here.
notice the
q
in one of the variable namescapture_thread.moveToThread(capture_qthread); process_thread.moveToThread(process_qthread);
terrible naming choice, but not the anti pattern you warning about
-
This post is deleted!