Qt 5 : update QProgressBar during QThread work via signal - c++

I'm trying to update a QProgressDialog (owned by a QMainWindow class) along the execution of a QThread who process some time consuming operations. The thread emit some signals during operation in order to inform the calling app about progression. I'm looking to connect the progress signal emitted by the thread to the setValue slot of the QProgressDialog in order to update the progress bar.
It doesn't work ! The progress dialog is not displayed. If I add a slot in my QMainWindow and connect it to the worker progress signal in order to display the value given by the thread throught qDebug output, I see that signals seems to be stacked during the threaded operation and unstacked only at the end of the thread.
I have tryed the DirectConnection connect's option without any success.
Here is my code :
qapp.cpp
#include "qapp.h"
#include <threaded.h>
#include <QVBoxLayout>
#include <QPushButton>
#include <QDebug>
#include <QProgressDialog>
QApp::QApp(QWidget *parent) :
QMainWindow(parent)
{
QVBoxLayout *mainLayout = new QVBoxLayout(this);
QWidget *window = new QWidget(this);
window->setLayout(mainLayout);
setCentralWidget(window);
QPushButton *button = new QPushButton("Run");
mainLayout->addWidget(button);
connect(button, SIGNAL(clicked(bool)), this, SLOT(doSomeWork()));
}
void QApp::doSomeWork()
{
qDebug() << "do some work";
Threaded worker;
worker.doHeavyCaclulations();
QProgressDialog progressDialog("Copying files...", "Abort Copy", 0, 10000, this);
progressDialog.setWindowModality(Qt::WindowModal);
progressDialog.setMinimumDuration(0);
progressDialog.setValue(0);
connect(&worker, SIGNAL(progress(int)), &progressDialog, SLOT(setValue(int)));
connect(&worker, SIGNAL(progress(int)), this, SLOT(displayProgress(int)));
worker.wait();
qDebug() << "end of thread";
}
void QApp::displayProgress(int value)
{
qDebug() << "data received" << value;
}
QApp::~QApp()
{
}
threaded.cpp :
#include "threaded.h"
#include <QDebug>
Threaded::Threaded(QObject *parent) : QThread(parent)
{
}
void Threaded::doHeavyCaclulations()
{
if (!isRunning())
{
qDebug() << "start thread" ;
start();
}
}
void Threaded::run()
{
qDebug() << "running big loop";
for(double k = 0 ; k < 10000 ; k++)
{
qDebug() << k;
emit progress(k);
}
}
qapp.h
#ifndef QAPP_H
#define QAPP_H
#include <QMainWindow>
class QApp : public QMainWindow
{
Q_OBJECT
public:
explicit QApp(QWidget *parent = 0);
~QApp();
private:
private slots:
void doSomeWork();
void displayProgress(int value);
};
#endif // QAPP_H
threaded.h
#ifndef THREADED_H
#define THREADED_H
#include <QObject>
#include <QThread>
class Threaded : public QThread
{
Q_OBJECT
public:
explicit Threaded(QObject *parent = 0);
void doHeavyCaclulations();
void run();
private:
signals:
void progress(int value);
public slots:
};
#endif // THREADED_H
The output of this code with k < 100 is :
do some work
start thread
running big loop
0
1
2
3
[...]
97
98
99
end of big loop
end of thread
data received 17
data received 18
data received 19
[...]
data received 99
If I remplace
worker.wait();
by
int k=0;
while(worker.isRunning())
{
qDebug() << "main " << k;
k++;
}
I get outputs of the thread and output of the calling method interleaved. It confirm that my thread is independant of the calling method.
Any idea about what I'm doing wrong ?

Absolutely wrong using of QThread). See what is the correct way to implement a QThread... (example please...). You need to learn thread's basics.
Your mistakes:
1. Create a static thread object in a local scope;
2. Wait for its finish in the main thread;
3. Don't start the thread;
4. Direct call method doHeavyCaclulations() in the main thread;
5. emit signal without working event loop for its deliver...
For your purpose you need:
Don't inherit QThread. Just create simple Work class with the necessary function:
class Work: public QObject
{
Q_OBJECT
public:
Work(){};
virtual ~Work(){};
public slots:
void doHeavyCaclulations() { /* do what you need and emit progress signal */ };
signals:
void progress(int);
}
// Then:
void QApp::doSomeWork()
{
//...
QThread* thread = new QThread(parent);
Work* worker = new Work; // Do not set a parent. The object cannot be moved if it has a parent.
worker->moveToThread(thread);
connect(thread, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(thread, SIGNAL(started()), worker, SLOT(doHeavyCaclulations()));
connect(worker, SIGNAL(progress(int)), &progressDialog, SLOT(setValue(int)));
thread->start();
//...
}

QThread has one very important thing you have to always remember when working with it - only the run() actually runs in a separate thread.
Whenever you create an instance of QThread this instance's thread affinity (the thread it belongs to) is the same thread where you have created it in. What's the big deal with that and what does it have to do with my slots and signals you may ask? Well, it has a lot to do with these things. Because only run() runs inside a separate thread you have to consider the following:
Signals belong to the instance ergo signals have a different thread affinity then the run()
Slots belong to the instance ergo slots have a different thread affinity then the run() - accessing shared data that is processed both inside a slot and inside run() requires explicitly employing thread-safety mechanisms such as mutexes and semaphores
If you do a lot of stuff inside your slots you will still freeze your UI as if you are not using your QThread
That said there are some scenarios where you may want to/have to employ slots and signals in a QThread but such implementation would have to be directed towards controlling the instance of QThread and not what it's actually running in a separate thread (using run()).
Here is a small demo I have written as a demonstration of how to implement slots and signals and interact with a separate thread using QObject. It employs slots and signals. Note that the usage of QThread is actually not necessary. You can also use a QRunnable for example (though you have to explicitly tell it to inherit from QObject too or to use a separate subclass of QObject created by you because QRunnable doesn't support slots and signals (it's not a subclass of QObject).
The advantage of using a QObject is that you can move its instance to the thread that is change it's thread affinity so that it completely runs in that separate thread (slots included). You can also put multiple QObject instances inside a single QThread if you want to. When inheriting a QThread and using it instead of this model you are limiting your options quite a bit.
So my advice here is dump the QThread implementation and go for the QThread + QObject (also know as Worker design pattern) way of doing things (for this particular scenario that is).

Related

QT slot not getting called on main thread

From the thread context of a slot in my QT GUI application (upon button push), I am trying to launch a worker thread to update other another part of the GUI with the results of a CPU intensive calculation - these results will update a table or a google like map widget - so this needs to occur in the main QT application thread where it is safe to update these widgets.
The problem I have is that the updateGUIWidget slot never gets called unless I change the connection type to Qt::DirectConnection - in which case it gets called in the worker thread (where it is unsafe to update the GUI). I checked the results of each of the connect calls and they are fine, it seems that there is some issue with the event loop somewhere. I'm not sure if I need to allocate the thread and the worker objects as members of the mainwindow or if its OK to do so from stack variables in the slot.
void
mainwindow::on_importSimulatedFlight_clicked()
{
// experimental worker thread model adapted from YouTube tutorial
// by Giuseppe di Angelo https://www.youtube.com/watch?v=BgqT6SIeRn4
// auto thread = new QThread;
// note worker created in gui thread here - we will move its thread
// affinity to 'thread' below before starting it.
auto thread = new QThread;
auto worker = new Worker;
connect(thread, &QThread::started, worker, &Worker::doWork);
// connect(worker, &Worker::progressUpdate, this, &mainwindow::updateGUIWidget, Qt::DirectConnection);
connect(worker, &Worker::progressUpdate, this, &mainwindow::updateGUIWidget, Qt::QueuedConnection);
connect(worker, &Worker::workDone, thread, &QThread::quit);
connect(thread, &QThread::finished, worker, &Worker::deleteLater);
// move worker to separate thread
worker->moveToThread(thread);
thread->start();
}
The mainwindow has a slots declared in mainwindow.h as follows:
class mainwindow : public QMainWindow
{
Q_OBJECT
public:
explicit mainwindow(QWidget *parent = Q_NULLPTR);
~mainwindow();
...
public slots:
void on_importSimulatedFlight_clicked();
void updateGUIWidget(const param& rParam);
...
}
and implemented in mainwindow.cpp as follows:
void
mainwindow::updateGUIWidget(const param& rParam)
{
... update widget components with rParam partial result here
}
and my worker is as follows:
class Worker : public QObject
{
Q_OBJECT
public slots:
void doWork() {
const QString result;
for (int i=0; i<5; i++) {
const MMRTimedRecord foo;
// QThread::sleep(1);
emit progressUpdate(foo);
}
emit workDone(result);
}
signals:
void progressUpdate(const MMRTimedRecord&);
void workDone(const QString &result);
};
The reason it isn't working is because there's a serious flaw in your code: you are trying to emit a reference to a local variable to be handled in an slot on a different thread. That is a recipe for disaster.
When you are using Qt::QueuedConnection, you MUST emit by value, like this:
void progressUpdate(MMRTimedRecord val);
That means that your MMRTimedRecord must be copyable, and correspondingly, your slot must also accept by value. And why is there a mismatch between the signal progressUpdate(const MMRTimedRecord&) and the slot updateGUIWidget(const param& rParam); ?
You can check this answer for a possible solution. You can do
MainThreadEvent::post([&]()
{
// gui update stuff
}
);
in your slot to do the gui update in the main thread, but it is a crude approach to be sure. Despite this, I do something like this all the time. Be careful of dangling pointers and references (use QPointer)..., as the issued event is independent of the issuing object. Alternatively, use the timer approach.
It’s really easy – and you shouldn’t be managing any threads manually:
void Ui::slot() {
QtConcurrent::run([this]{
auto result = compute();
QMetaObject::invokeMethod(this, [this, r = std::move(result)]{
m_widget.setSomething(r);
});
});
}
The type of the data you compute should be movable.

QMutex in slots

Suppose to have the following QT code (QT 5.3.1):
void SenderClass::runSignal()
{
emit mySignal();
}
void ReceiverClass::ReceiverClass()
{
...
connect (senderClassRef, SIGNAL(mySignal()), this, SLOT(mySlot()) );
}
void ReceiverClass::mySlot()
{
//Long operation executions
Sleep(1000);
qDebug() << "1";
Sleep(1000);
qDebug() << "2";
Sleep(1000);
qDebug() << "3";
}
Calling runSignal() consecutively it happens that console displays something like:
1 2 1 3 2 3
The 2 classes live in the same thread.
Do I have to use a QMutexLocker in slots?? Or is there an another way to have an ordered output like:
1 2 3 1 2 3
so preventing a call of mySlot() function if there's still one executing.
UPDATE
Here follow a real code snippet.
The sender:
//Sender.h
#include <QtWidgets/QWidget>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QTextBrowser>
class Receiver;
class Sender : public QWidget
{
Q_OBJECT
public:
Sender(QWidget *parent = 0);
QPushButton *pushButton;
QTextBrowser *textBrowser;
Receiver* receiver;
signals:
void buttonClickedSignal();
public slots:
void ButtonClickedSlot();
};
//Sender.cpp
#include "Sender.h"
#include "Receiver.h"
#include <QObject>
Sender::Sender(QWidget *parent)
: QWidget(parent)
{
pushButton = new QPushButton(this);
pushButton->setObjectName(QStringLiteral("pushButton"));
pushButton->setGeometry(QRect(150, 30, 75, 23));
pushButton->setText("Button");
textBrowser = new QTextBrowser(this);
textBrowser->setObjectName(QStringLiteral("textBrowser"));
textBrowser->setGeometry(QRect(50, 90, 256, 192));
receiver = new Receiver(this);
QObject::connect(pushButton, SIGNAL(clicked()), this, SLOT(ButtonClickedSlot()));
}
void Sender::ButtonClickedSlot()
{
emit buttonClickedSignal();
}
The receiver:
//Receiver.h
#include "Sender.h"
class Receiver : QObject
{
Q_OBJECT
public:
Receiver(Sender *sender);
Sender *m_sender;
public slots:
void ReceiverSlot();
};
//Receiver.cpp
#include "Receiver.h"
#include <QObject>
#include <QThread>
#include <QApplication>
Receiver::Receiver(Sender *sender)
{
m_sender = sender;
QObject::connect(m_sender, SIGNAL(buttonClickedSignal()), this, SLOT(ReceiverSlot()), Qt::QueuedConnection);
}
void Receiver::ReceiverSlot()
{
m_sender->textBrowser->append("1");
QThread::msleep(100);
qApp->processEvents();
m_sender->textBrowser->append("2");
QThread::msleep(100);
qApp->processEvents();
m_sender->textBrowser->append("3");
QThread::msleep(100);
qApp->processEvents();
m_sender->textBrowser->append("4");
QThread::msleep(100);
qApp->processEvents();
}
Clicking the button quickly results in not consecutive numbers in QTextBrowser, even if a QueuedConnection is set.
UPDATE 2
What I would like to achieve is a queued access to the ReceiverSlot. The user can click the button with any freedom (when he wants and at any speed). The ReceiverSlot cannot miss any event. I need some sort of event queuing so that (long) operations in the ReceiverSlot are always executed, maybe delayed, but executed.
Get rid of QApplication::processEvents and move the long operation that freezes your GUI to a new thread. You can use for example a worker object that you move to a new thread. There is a good example of this in the docs.
You should also read this to learn more about threads and events in Qt. There is an exact same situation as yours explained in the forcing event dispatching part:
Be very careful when reentering the event loop “by other paths”: it can lead to unwanted recursions! Let’s go back to the Button example. If we call QCoreApplication::processEvents() inside the doWork() slot, and the user clicks again on the button, the doWork() slot will be invoked again:
main(int, char **) QApplication::exec()
[…]
QWidget::event(QEvent *)
Button::mousePressEvent(QMouseEvent *)
Button::clicked()
[…]
Worker::doWork() // first, inner invocation
QCoreApplication::processEvents() // we manually dispatch events and…
[…]
QWidget::event(QEvent * ) // another mouse click is sent to the
Button…
Button::mousePressEvent(QMouseEvent *)
Button::clicked() // which emits clicked() again…
[…]
Worker::doWork() // DANG! we’ve recursed into our slot.
In general you want to avoid QApplication::processEvents and creating local event loops. If you have these in your code, then you should redesign it so you won't have to use these.
Worker object examlpe from the docs:
class Worker : public QObject
{
Q_OBJECT
QThread workerThread;
public slots:
void doWork(const QString &parameter) {
// ...
emit resultReady(result);
}
signals:
void resultReady(const QString &result);
};
class Controller : public QObject
{
Q_OBJECT
QThread workerThread;
public:
Controller() {
Worker *worker = new Worker;
worker->moveToThread(&workerThread);
connect(workerThread, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(this, SIGNAL(operate(QString)), worker, SLOT(doWork(QString)));
connect(worker, SIGNAL(resultReady(QString)), this, SLOT(handleResults(QString)));
workerThread.start();
}
~Controller() {
workerThread.quit();
workerThread.wait();
}
public slots:
void handleResults(const QString &);
signals:
void operate(const QString &);
};
To turn my comments into a proper answer:
If, when in your slot you call qApp->processEvents() there is a mouse press event waiting to be delivered to the button, it will be delivered, and the clicked() signal will be emitted again, and thus your slot will be called again.
A QMutex will not help, because there is no threading involved. Adding one would most likely result in your program deadlocking.
Using Qt::QueuedConnection doesn't help, because this posts an event to the queue which, when processed, will result in your slot being invoked. So it just, at best, delays it until the next time you call qApp->processEvents().
In the context of your example, my suggestion would be to get rid of the queued connection, and instead disable the button while the slot is working. This will prevent the clicked() signal being emitted again, and also show the user that they shouldn't be trying to click on the button at this time.
If for whatever reason you don't want to do that, you could add a flag to your receiver class to prevent recursive calls. Something like this will do the trick, although it's not very pretty:
void Receiver::ReceiverSlot()
{
if( m_inSlot )
return;
m_inSlot = true;
// do work
m_inSlot = false;
}

Create Thread in QDialog and emit signals to QDialog in Qt

I created an application that has a mainwindow and from this window creates a QDialog. This QDialog should create a RenderThread that emits received images from the camera or in the example emits text. When i debug this it seems that the connection is never made as adding a breakpoint in the slot CameraWindow::debugSomething does not get caught. Whats wrong ?
I followed this example: http://qt-project.org/doc/qt-4.8/threads-mandelbrot.html but it seems that i've done something wrong.
qtDEVC::qtDEVC(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
ui.setupUi(this);
connect (ui.pushButton_startCam, SIGNAL( clicked() ),this,SLOT( startCam() ) );
/**Threading*/
CameraWindow camWindow = new CameraWindow(this);
}
int qtDEVC::startCam()
{
camWindow.show();
camWindow.startCaptureThread();
}
CameraWindow Class:
CameraWindow::CameraWindow(QWidget *parent)
: QDialog(parent)
{
ui.setupUi(this);
connect(&thread, SIGNAL(sendText(std::string)),
this, SLOT(debugSomething(std::string)));
}
void CameraWindow::debugSomething(std::string something){
QString somethings(something.c_str());
qDebug()<<somethings;
}
int CameraWindow::startCaptureThread(){
RenderThread *thread = new RenderThread(this, guid, CLEYE_COLOR_RAW, CLEYE_VGA, 50);
thread->StartCapture(); //starts thread in low priority and sets _running to true
}
CameraWindow header
class CameraWindow : public QDialog
{
Q_OBJECT
public:
CameraWindow(QWidget *parent = 0);
~CameraWindow();
Ui::CameraWindow ui;
public slots:
int startCaptureThread();
void debugSomething(QString);
private:
RenderThread thread;
};
RenderThread Class
void RenderThread::run()
{
// image capturing loop
while(_running)
{
qDebug()<<("render while()"); //is printed with qdebug correctly
if (restart)
break;
if (abort)
return;
qDebug("it"); //is also printed with qdebug correctly
emit sendText(text);
}
RenderThread header
class RenderThread : public QThread
{
Q_OBJECT
public:
RenderThread(QObject *parent, GUID cameraGUID, CLEyeCameraColorMode mode, CLEyeCameraResolution resolution, float fps);
RenderThread();
~RenderThread();
bool StartCapture();
signals:
void sendText(QString &text);
protected:
void run();
private:
QMutex mutex;
QWaitCondition condition;
//some more private variables for construction
};
I think that this creation seems somehow wrong: RenderThread *thread = new RenderThread(this);
The first thing that's worrying about the question is the word "RenderThread". Note that Qt only allows rendering on the main thread. You can create separate threads for calculations of image data, but whenever you use a painter and draw objects, that must happen on the main thread. However, If you're just going to capture the image and pass that to the main thread, via signals and slots, then that should be ok.
Secondly, whilst you've not shown all your code, I'm assuming from the function called RenderThread::run() and from the Qt example that you may have inherited from QThread here. If this is the case, please note that this is not how to use QThread. Instead, you should have your class inherit from QObject and move that to a QThread. You can read about how to use QThread properly here.
I know it's a Qt example that you've followed, but even the guys at Qt think it's a bad idea. Here's an article of how to really use QThreads.
With that in mind, here's an outline of how I would use QThread for this: -
class CameraWindow : public QDialog
{
private:
CameraObject* m_pCamObject;
};
class CameraObject : public QObject
{
Q_OBJECT
public:
private slots:
startCaptureThread();
private:
};
int CameraWindow::startCaptureThread()
{
m_pCamObject = new CameraObject;
QThread* pThread = new QThread;
this->moveToThread(pThread); // CameraObject will run on the new thread
connect(pThread, SIGNAL(started()), m_pCamObject, SLOT(startCaptureThread()));
connect(pThread, SIGNAL(finished()), pThread, SLOT(deleteLater()); // clear up when
finished
pThread->start();
}
Note that here is a CameraObject, separated from the CameraWindow. The QThread is just a controller of the thread and keeps a clean separation from the CameraObject.
Another reason for handling threads this way is that you can move multiple QObject instances to the new thread, rather than always creating a new thread per object. If you've more threads than CPU cores, you're unlikely to gain by creating yet another thread.
In the constructor of CameraWindow class, you are connecting a RenderThread's signal but it is not the same object which is started in startCaptureThread. Change your startCaptureThread like this:
int CameraWindow::startCaptureThread()
{
thread.StartCapture(); //starts thread in low priority and sets _running to true
}
In this method, the thread member of CameraWindow is started.
P.S.: post the headers too, we can't see the members from this code.
In the mentioned example, CameraWindow class holds a RenderThread thread variable, not a RenderThread *thread.
You are connecting a pointer address in your connect call:
connect(&thread, SIGNAL(sendText(std::string)),
this, SLOT(debugSomething(std::string)));
Try to use a good address:
connect(thread, SIGNAL(sendText(std::string)),
this, SLOT(debugSomething(std::string)));
This is not a tested answer.

Issues with Qt's signals and slots behavior with multithreading

I'm currently trying to understand how signals and slots in Qt behave with threads.
I've tried to run a small test with the following code:
class Worker : public QObject{
Q_OBJECT
public:
Worker(int _value){value = _value;}
~Worker(){};
int value;
public slots:
void changeValue(int newValue){value = newValue;}
void doWork(){
while(1){
_sleep(500);
std::cout << "Value is " << value << std::endl;
if(value == 0)break;
}
emit finished();
}
signals:
void finished();
};
class Manager : public QObject{
Q_OBJECT
public:
Manager(){}
~Manager(){};
signals:
void modifiedValue(int value);
public:
void changeTheValue(int value){emit modifiedValue(value);}
};
Basically, the worker display its value member every once in a while, and has a slot with a function that modifies the value.
The manager has the only purpose of emitting a signal with a new value when changeTheValue is called, that maps to the slot in Worker that modifies the value member.
Then I make my Worker class work in a thread the following way :
QThread myThread;
Worker myWorker(10);
Manager manager;
myWorker.moveToThread(&myThread);
QObject::connect(&myThread, SIGNAL(started()), &myWorker,SLOT(doWork()));
QObject::connect(&myWorker, SIGNAL(finished()), &myThread, SLOT(quit()));
QObject::connect(&myWorker, SIGNAL(finished()), &myWorker, SLOT(deleteLater()));
QObject::connect(&myThread, SIGNAL(finished()), &myThread, SLOT(deleteLater()));
QObject::connect(&manager, SIGNAL(modifiedValue(int)),
&myWorker, SLOT(changeValue(int)));
myThread.start();
for(int i = 1; i < 10 ; i++){
_sleep(1000);
manager.changeTheValue(i);
}
manager.changeTheValue(0);
But nothing happens. The value doesn't seem to be changed: output show a dozen lines with Value is 10.
What I can't understand is, why does the signal/slot mapping with Manager::modifiedValue and Worker::changeValue does not seem to work ? Is it only because the thread is currently running the doWork()'s loop ? Where does the call to the slots ends up then (queued, discarded, other) ?
I couldn't find much more on how does the signals/slots mechanism work with threads (I only found this thread which explains in which thread's call stack does the call to the slot end up, but the link provided in the answer seems outdated and leads to Qt 5 home).
To sum up the questions:
Why does the call to the slot that modifies the value does nothing ?
Is it possible to make this work (adding thread-safety wherever necessary) and how ?
There are multiple modes of how signals and slots work with threads (you absolutely must use QThreads for these to work!). These are documented in the manual:
http://qt-project.org/doc/qt-4.8/threads-qobject.html#signals-and-slots-across-threads
The mistake in your code is that the Qt event loop is never called (as doWork never returns). For a repeating call you should be using a timer in that thread. Alternatively (NOT the recommended solution) you can call processEvents in your infinite loop.

QThread related problems

I'm having some problems and questions about QThread.
1) When I use QThread->quit(), finished() signal is not emitted..
2) How is right way to build and finish execution of thread?
1) finished signal code - the header file.
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
class MyThread: public QThread
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = 0);
signals:
public slots:
void finished();
protected:
void run();
};
#endif // MYTHREAD_H
1) CPP file.
#include "MyThread.h"
MyThread::MyThread(QObject *parent) :
QThread(parent)
{
}
void MyThread::finished()
{
//never gets called...
qDebug() << "Finished.";
}
void MyThread::run()
{
connect(this, SIGNAL(finished()), this, SLOT(finished()), Qt::DirectConnection);
this->exec();
}
I'm building it with this:
MyThread *mThread = new MyThread(this); //What does parent do/mean ?
mThread->start();
Sleep(5000); //Windows.
mThread->quit(); //Finish thread.
I even don't understand what Qt::DirectConnection does, I already read documentation, but I don't really get it how and when to use Direct/Queued connections.
Another questions that came to my mind just now.
1) How can I finish and cleanup thread from self? (I mean, thread should quit by itself and do cleanup.)
2) How to proper why of creating/running new thread and why?
Thank you.
Don't sub-class QThread. Instead, create a worker object (that inherits QObject), create a QThread, then call the moveToThread() method on your worker object.
class Worker : public QObject
{
Q_OBJECT
public:
Worker( QObject * parent = 0 )
: QObject( parent )
{
connect( this, SIGNAL(done()), \
this, SLOT(deleteLater())
);
}
public slots:
void doWork() { // work, work }
signals:
void done(); // emit this when you're finished with the work
};
// in your main function (or wherever)
QThread * thread = new QThread();
Worker * w = new Worker();
w->moveToThread( thread );
thread->start();
// clean up your thread
QObject::connect( w, SIGNAL(destroyed()), thread, SLOT(quit()) );
QObject::connect( thread, SIGNAL(finished()), thread(deleteLater()) );
// at some point, emit a signal connected to your workers 'doWork()' slot.
// when the work is finished, the worker and thread will both clean themselves up.
Edit: What if I'm using an older version of Qt?
In recent Qt releases, the default implementation of the QThread::run() method is to call exec(), which starts the thread's event loop. If you're supporting an older version of Qt, you do need to subclass QThread in order for the above code to work.
class MyThread : public QThread
{
void run() { exec(); }
};
Then, just use MyThread instead of QThread, and all of the above still applies. In this case, it makes perfect sense to subclass QThread because you're creating a specialized thread class (one that runs its own event loop when you call start()).
As for thread clean-up, the above still applies.
QObject::connect( thread, SIGNAL(finished()), thread, SLOT(deleteLater()) );
When you call MyThread::quit(), the event loop will return, run() will return, then the thread object emits the finished() signal. Since the MyThread object actually lives in the main event loop, the deleteLater() slot invocation will still be delivered.