Qt Add loading widget screen while opening a project - multithreading

I created an application in which I would like to add a loading screen when the application is opening a project because the loading of the project can be long and sometimes, the gui blocks so the user can think there is a crash.
So I tried with QThread, reading doc and "solved" examples on this forum but nothing to do, I can't make it work.
I have a MainWindow class which deals with GUI and this class is the one I create in the main function :
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
Then I have :
mainwindow.h
class MyThread;
class MainWindow : public QMainWindow
{
Q_OBJECT
...
private :
Controller *controller;//inherits from QObject and loads the project
QList<MyThread*> threads;
public slots :
void animateLoadingScreen(int inValue);
}
mainwindow.cpp
MainWindow::MainWindow(...)
{
controller=new Controller(...);
threads.append(new MyThread(30, this));
connect(threads[0], SIGNAL(valueChanged(int)), this, SLOT(animateLoadingScreen(int)));
}
void MainWindow::animateLoadingScreen(int inValue)
{
cout<<"MainWindow::animateLoadingScreen"<<endl;
widgetLoadingScreen->updateValue(inValue);//to update the animation
}
void MainWindow::openProject()
{
widgetLoadingScreen->show()://a widget containing a spinner for example
threads[0]->start();//I want to launch the other thread here
controller->openProject();
threads[0]->exit(0);//end of thread so end of loading screen
}
MyThread.h
class MyThread : public QThread
{
Q_OBJECT;
public:
explicit MyThread(int interval, QObject* parent = 0);
~MyThread();
signals:
void valueChanged(int);
private slots:
void count(void);
protected:
void run(void);
private:
int i;
int inc;
int intvl;
QTimer* timer;
};
MyThread.cpp
MyThread::MyThread(int interval, QObject* parent): QThread(parent), i(0), inc(-1), intvl(interval), timer(0)
{
}
void MyThread::run(void)
{
if(timer == 0)
{
timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(count()));
}
timer->start(intvl);
exec();
}
void MyThread::count(void)
{
if(i >= 100 || i <= 0)
inc = -inc;
i += inc;
emit valueChanged(i);
}
When I execute the app, and click on open button which launches MainWindow::openProject(), I get :
QObject: Cannot create children for a parent that is in a different thread.
(Parent is MyThread(0x5463930), parent's thread is QThread(0x3cd1f80), current thread is MyThread(0x5463930)
MainWindow::animateLoadingScreen
MainWindow::animateLoadingScreen
....
MainWindow::animateLoadingScreen
MainWindow::animateLoadingScreen
(and here the controller outputs. and no MainWindow::animateLoadingScreen anymore so the widget loading screen is never animated during the opening of the project)
So what do I have to do, what do I have to put in MyThread class, how to link its signal to MainWindow to update the loading screen. And I think that there may be a problem with widgetLoadingScreen which is created in MainWindow so if MainWindow is blocked beacause of the opening, the widgetLoadingScreen can't be updated since it is in the thread of MainWindow which handles the GUI ?!
I read :
http://www.qtcentre.org/wiki/index.php?title=Updating_GUI_from_QThread
but with that one, I got error message at runtime, it's the one I use in the code I give above
QObject: Cannot create children for a parent that is in a different thread.
(Parent is MyThread(0x41938e0), parent's thread is QThread(0x1221f80), current thread is MyThread(0x41938e0)
I tried that too :
How to emit cross-thread signal in Qt?
but, even if I don't have the error message at runtime, it's the same for the animation which is not updated.
I am completely lost, and I don't think it's something difficult to do to have a loading screen in a thread while the main thread is opening a project?!

Qt has a QSplashScreen class which you could use for a loading screen.
Besides this, one of the problems you have is due to thread affinity (the thread in which an object is running) and the fact that you've decided to inherit from QThread.
In my opinion, QThread has a misleading name. It's more of a thread controller and unless you want to change how Qt handles threads, you really shouldn't inherit from it and many will tell you that "You're doing it Wrong!"
By inheriting QThread, your instance of MyThread is running on the main thread. However, when a call to exec() is made, it starts the event loop for the new thread and all its children, which includes the QTimer, and tries to move it to the new thread.
The correct way to solve this is not to inherit from QThread, but to create a worker object, derived from QObject and move it to the new thread. You can read about how to 'Really Truly Use QThread' here.

1st problem - runtime error with QTimer
Problem is in void MyThread::run(void), line timer = new QTimer(this);. The thread instance is created in (and so owned by) different (main) thread then it represents. For this reason, you cannot use thread as parent for object created inside the thread. In your case, solution is simple - create the timer on stack.
Example:
void MyThread::run(void)
{
QTimer timer;
connect(&timer, SIGNAL(timeout()), this, SLOT(count()));
timer.start(intvl);
// Following method start event loop which makes sure that timer
// will exists. When this method ends, timer will be automatically
// destroyed and thread ends.
exec();
}
2nd problem - GUI not updating
Qt requires the GUI to be created and displayed from main application thread. This means that blocking main thread with big operation blocks whole GUI. There are only 2 possible solutions:
Move the heavy work to other (loading) thread. This is best solution and I believe it's worth the effort (I'm aware you wrote that this would be problematic).
During the heavy operation, call regularly QCoreApplication::processEvents() - each time you call this, events will be processed, which includes calling slots, key and mouse events, GUI redraw etc. The more often you call this, the more responsive GUI will be. This is simpler to implement (just put one line all over the code), but it's quite ugly and if the operation blocks on loading a file, the GUI will freeze for some time. That means that responsiveness of your GUI depends on interval between calls. (But if you call it too often, you will slow down the loading progress.) This technique is discouraged and it's best to avoid it...

The way I will do it based on the default example on Qthread Page:
Break the big controller->openProject(); such that it updates a variable
provide access to that variable using a signal ( like statusChanged(int)).
Do what you need to do once the signal is triggered.
The code looks like
class Worker : public QObject
{
Q_OBJECT
QThread workerThread;
private:
int status; //
bool hasworktoDo();
void doSmallWork();
public slots:
void doWork() {
while(hasworktoDo())
{
doSmallWork(); // fragments of controller->openProject();
++status; //previously set to 0
emit statusChanged(status);
}
emit resultReady(result);
}
signals:
void resultReady(const QString &result);
void statusChanged(int value);
};
class Controller : public QObject
{
Q_OBJECT
QThread workerThread;
public:
Controller() {
Worker *worker = new Worker;
worker->moveToThread(&workerThread);
connect(workerThread, SIGNAL(statusChanged(int)), this, SLOT(updateStatus(int)));
connect(workerThread, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(this, SIGNAL(operate()), worker, SLOT(doWork()));
connect(worker, SIGNAL(resultReady(QString)), this, SLOT(handleResults(QString)));
workerThread.start();
}
~Controller() {
workerThread.quit();
workerThread.wait();
}
public slots:
void handleResults(const QString &);
void updateStatus(int value)
{
int status = value;
//now you have what to use to update the ui
}
signals:
void operate(); //
};
If you have trouble breaking the openProject operations in small parts, it just mean it is pointless to say on the UI that you are at 50%... Just say Loading... and make the code simpler. Note that you don't need a timer in my case, as the worker sends regular updates

Related

waitForReadyRead() in subthread freezes the GUI thread

Sorry for my poor English :(
I use a class named SerialPort inherited from QObject:
serial_port.cpp & serial_port.h:
class SerialPort: public QObject{
Q_OBJECT
private:
bool checkStatusConnected();
private slots:
void readData();
}
bool SerialPort::checkStatusConnected(){
port.waitForReadyRead(200);
QBytesArray recv = port.readAll();
QString tmp = (QString)recv;
if(tmp.contains("Connected", Qt::CaseInsensitive))
return true;
return false;
}
MainWindow.cpp
void MainWindow::on_btnConn_clicked()
{
QThread* thread = new QThread(this);
serialport->moveToThread(thread);
serialport->connect();
}
In SerialPort::connect() I opened the port and send the connect command. Till now everything is ok. Due to slow speed of serial port I need to check the string return to me before next actions, so in SerialPort::connect() I call checkStatusConnected(). However, in this function waitForReadyRead() freezes the GUI thread as long as the time I set which makes me confused.
Why is the GUI thread blocked by another QThread and how to solve this problem?
Thanks!
You don't need to use threads for that. QSerialPort is event driven and works asynchronously. Use a timer to see whether you have received something within the required time.
QSerialPort port(....);
connect(&port, SIGNAL(readyRead()), this, SLOT(readFromSerialPort()));
QTimer timer;
timer.setInterVal(1000); // time you want to wait
connect(&timer, SIGNAL(timeout()), this, SLOT(handleTimeout()));
void SomeClass::readFromSerialPort()
{
QByteArray data(port.readAll());
// do somework
}
Found the examples. Check this out, this will suffice your needs I think.
http://doc.qt.io/qt-5/qtserialport-creaderasync-example.html

Play QSoundEffect in QThread

I can not get the QSoundEffect to play in a separate thread. Could you please tell me why is the sound played only by the first code snippet and not by the second?
//main.cpp
#include <QCoreApplication>
#include "SoundThread.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// #1
QSoundEffect alarmSound;
alarmSound.setSource(QUrl::fromLocalFile(":/sound"));
alarmSound.play();
/* #2
SoundThread thread;
thread.start();
thread.wait();
*/
return a.exec();
}
and
//SoundThread.h
#ifndef SOUNDTHREAD_H
#define SOUNDTHREAD_H
#include <QThread>
#include <QtMultimedia/QSoundEffect>
class SoundThread : public QThread
{
Q_OBJECT
private:
void run()
{
QSoundEffect alarmSound;
alarmSound.setSource(QUrl::fromLocalFile(":/sound"));
alarmSound.play();
while(true){}
}
};
#endif // SOUNDTHREAD_H
From the Qt documentation on QThread: -
By default, run() starts the event loop by calling exec()
Since you've inherited from QThread, you now have a run function which doesn't call exec(). Therefore, the event loop is not running and is most likely required for playing the sound effect.
Calling exec() should be substituted for the while(true){} as exec() will wait until exit() is called.
Doing it properly, with moving an object to the thread, based on "How to Really Truly Use QThreads..."
class Worker : public QObject
{
Q_OBJECT
public:
Worker();
~Worker();
public slots:
void PlaySoundEffect();
signals:
void finished();
void error(QString err);
private:
// store the sound effect, so we can reuse it multiple times
QSoundEffect* m_pAlarmSound;
private slots:
};
Worker::Worker()
{
m_pAlarmSound = new QSoundEffect;
m_pAlarmSound.setSource(QUrl::fromLocalFile(":/sound"));
}
Worker::~Worker()
{
delete m_pAlarmSound;
m_pAlarmSound = nullptr; // C++ 11
}
void Worker::PlaySoundEffect()
{
m_pAlarmSound->play();
}
// setup the worker and move it to another thread...
MainWindow::MainWindow
{
QThread* thread = new QThread;
Worker* worker = new Worker();
worker->moveToThread(thread);
connect(worker, SIGNAL(error(QString)), this, SLOT(errorString(QString)));
connect(thread, SIGNAL(started()), worker, SLOT(PlaySoundEffect()));
connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
// We can also connect a signal of an object in the main thread to the PlaySoundEffect slot
// Assuming MainWindow has declared a signal void Alert();
connect(this, &MainWindow::Alert, worker, &Worker::PlaySoundEffect);
// Then play the sound when we want: -
emit Alert();
}
While this seems like a lot of effort, there are many advantages of doing it this way. If, for example, you have a lot of sound effects, the method of inheriting QThread means that you're creating a thread per sound effect, which isn't ideal.
We could easily extend the above Worker object to hold a list of sound effects and play the one we want, by passing an enum into the PlaySoundEffect slot. As this thread is constantly running, playing sounds will incur less delay; it takes time and resources to create a thread at run-time.
You enter to an infinite loop at the end of your run function which causes to block the thread and consequently the QSoundEffect not working. It should be like:
void run()
{
QSoundEffect alarmSound;
alarmSound.setSource(QUrl::fromLocalFile(":/sound"));
alarmSound.play();
exec();
}
Replace while(true){} by QThread::run();, which will launch an internal event loop and will wait (sleep) for events, such as timer events and asynchronous signals calling slots, which is probably what is happening internally in QSoundEffect: When you call QSoundEffect::play() Some event (probably signals/slots) are queued in the event queue from within QThread, but nothing is processing the event queue. Remember: you are overriding virtual void run() and the original implementation was calling QThread::exec() for you. It is always a good idea to always call your super classes virtual function whenever you override them, as long as they are not pure virtual.
void run()
{
QSoundEffect alarmSound;
alarmSound.setSource(QUrl::fromLocalFile(":/sound"));
alarmSound.play();
QThread::run();
}
Some people suggested that calling QThread::exec() would do the trick. They may be right. I have to check the implementation of QThread to confirm that it is the only thing called in QThread::run() implementation. I personally think (by experience) that it is always safer to call your superclasse's virtual function in case there are other things called (other than QThread::exec() for this particular case).
Another option would be to move your QSoundEffect instance onto the thread and use signals and slots default auto-connection behaviour type to switch threads.
SoundPlayer.h:
#ifndef SOUNDPLAYER_H_
#define SOUNDPLAYER_H_
#include <QObject>
#include <QThread>
#include <QSoundEffect>
class SoundPlayer : public QObject
{
Q_OBJECT
public:
SoundPlayer();
signals:
void play();
private:
QThread m_thread;
QSoundEffect m_alarmSound;
};
#endif
SoundPlayer.cpp :
#include "SoundPlayer.h"
SoundPlayer()
{
m_alarmSound.setSource(QUrl::fromLocalFile(":/sound"));
m_alarmSound.moveToThread(&m_thread);
connect(this, SIGNAL(play()), &m_alarmSound, SLOT(play()));
m_thread.start(); // QThread::exec() will be called for you, making the thread wait for events
}
And then calling the play() signal would start playing in the correct thread.
SoundPlayer player;
emit player.play(); // m_alarmSound.play() will be called by m_thread

QThread: Call a signal in the right thread [duplicate]

This question already has answers here:
QThread and QTimer
(4 answers)
Closed 8 years ago.
I have some very time consuming tasks to execute in a GUI application, and I want them to be threaded so it won't freeze my GUI..
To do so, I created a thread, and started a timer. I connected the timeout() method from my timer to the time-consuming function I want to paralellize, in the "run" method of my thread, but when the signal is called, the time-consuming function is called in the main thread instead of the one I created.
Here's my code, simplified for the example:
void MyThread::run()
{
m_pTimer = new QTimer()
connect(m_pTimer, SIGNAL(timeout()), this, SLOT(timeConsumingMethod()));
m_pTimer->start(x);
}
I printed the value of the static method QThread::currentThread() in "timeConsumingMethod", in MyThread::run() and in my main, and its value is the same as the one in my main.
How can I make my function run in the separated thread? And more important why is my code wrong?
"You’re doing it wrong." :)
try this:
myworker.h
#include ...
class MyWorker : public QObject {
Q_OBJECT
public:
explicit MyWorker(QObject* parent = 0);
public slots:
void timeConsumingMethod();
}
myworker.cpp
#include "myworker.h"
#include ...
MyWorker::MyWorker(QObject* parent) :
QObject(parent)
{
/*
...
*/
}
void MyWorker::timeConsumingMethod() {
/*
...
*/
}
code
/*...*/
MyWorker* worker = new MyWorker();
QThread* workerThread = new QThread();
QTimer* timer = new QTimer();
worker->moveToThread(workerThread);
worker->connect(timer, SIGNAL(timeout()), SLOT(timeConsumingMethod()));
// don't forget proper obj deletion
// not the best way, but...
worker->connect(workerThread, SIGNAL(destroyed()), SLOT(deleteLater());
workerThread->start();
timer->start(x);
in that case worker will "live" in workerThread. QT SIGNAL-SLOT mechanism supports connection between objects in different threads.
that approach much better than "procedural way" by reimplementing run() method and QThread inheritance
worker works, QThread controls thread
source: http://qt-project.org/wiki/Threads_Events_QObjects

Modify Qt GUI from background worker thread

I work in Qt and when I press the button GO I need to continuously send packages to the network and modify the interface with the information I receive.
The problem is that I have a while(1) in the button so the button never finishes so the interface is never updated. I thought to create a thread in the button and put the while(){} code there.
My question is how can I modify the interface from the thread? (For example how can I modify a textBox from the thread ?
Important thing about Qt is that you must work with Qt GUI only from GUI thread, that is main thread.
That's why the proper way to do this is to notify main thread from worker, and the code in main thread will actually update text box, progress bar or something else.
The best way to do this, I think, is use QThread instead of posix thread, and use Qt signals for communicating between threads. This will be your worker, a replacer of thread_func:
class WorkerThread : public QThread {
void run() {
while(1) {
// ... hard work
// Now want to notify main thread:
emit progressChanged("Some info");
}
}
// Define signal:
signals:
void progressChanged(QString info);
};
In your widget, define a slot with same prototype as signal in .h:
class MyWidget : public QWidget {
// Your gui code
// Define slot:
public slots:
void onProgressChanged(QString info);
};
In .cpp implement this function:
void MyWidget::onProgressChanged(QString info) {
// Processing code
textBox->setText("Latest info: " + info);
}
Now in that place where you want to spawn a thread (on button click):
void MyWidget::startWorkInAThread() {
// Create an instance of your woker
WorkerThread *workerThread = new WorkerThread;
// Connect our signal and slot
connect(workerThread, SIGNAL(progressChanged(QString)),
SLOT(onProgressChanged(QString)));
// Setup callback for cleanup when it finishes
connect(workerThread, SIGNAL(finished()),
workerThread, SLOT(deleteLater()));
// Run, Forest, run!
workerThread->start(); // This invokes WorkerThread::run in a new thread
}
After you connect signal and slot, emiting slot with emit progressChanged(...) in worker thread will send message to main thread and main thread will call the slot that is connected to that signal, onProgressChanged here.
P.s. I haven't tested the code yet so feel free to suggest an edit if I'm wrong somewhere
So the mechanism is that you cannot modify widgets from inside of a thread otherwise the application will crash with errors like:
QObject::connect: Cannot queue arguments of type 'QTextBlock'
(Make sure 'QTextBlock' is registered using qRegisterMetaType().)
QObject::connect: Cannot queue arguments of type 'QTextCursor'
(Make sure 'QTextCursor' is registered using qRegisterMetaType().)
Segmentation fault
To get around this, you need to encapsulate the threaded work in a class, like:
class RunThread:public QThread{
Q_OBJECT
public:
void run();
signals:
void resultReady(QString Input);
};
Where run() contains all the work you want to do.
In your parent class you will have a calling function generating data and a QT widget updating function:
class DevTab:public QWidget{
public:
void ThreadedRunCommand();
void DisplayData(QString Input);
...
}
Then to call into the thread you'll connect some slots, this
void DevTab::ThreadedRunCommand(){
RunThread *workerThread = new RunThread();
connect(workerThread, &RunThread::resultReady, this, &DevTab::UpdateScreen);
connect(workerThread, &RunThread::finished, workerThread, &QObject::deleteLater);
workerThread->start();
}
The connection function takes 4 parameters, parameter 1 is cause class, parameter 2 is signal within that class. Parameter 3 is class of callback function, parameter 4 is callback function within the class.
Then you'd have a function in your child thread to generate data:
void RunThread::run(){
QString Output="Hello world";
while(1){
emit resultReady(Output);
sleep(5);
}
}
Then you'd have a callback in your parent function to update the widget:
void DevTab::UpdateScreen(QString Input){
DevTab::OutputLogs->append(Input);
}
Then when you run it, the widget in the parent will update each time the emit macro is called in the thread. If the connect functions are configured properly, it will automatically take the parameter emitted, and stash it into the input parameter of your callback function.
How this works:
We initialise the class
We setup the slots to handle what happens with the thread finishes and what to do with the "returned" aka emitted data because we can't return data from a thread in the usual way
we then we run the thread with a ->start() call (which is hard coded into QThread), and QT looks for the hard coded name .run() memberfunction in the class
Each time the emit resultReady macro is called in the child thread, it's stashed the QString data into some shared data area stuck in limbo between threads
QT detects that resultReady has triggered and it signals your function, UpdateScreen(QString ) to accept the QString emitted from run() as an actual function parameter in the parent thread.
This repeats every time the emit keyword is triggered.
Essentially the connect() functions are an interface between the child and parent threads so that data can travel back and forth.
Note: resultReady() does not need to be defined. Think of it as like a macro existing within QT internals.
you can use invokeMethod() or Signals and slots mechanism ,Basically there are lot of examples like how to emit a signal and how to receive that in a SLOT .But ,InvokeMethod seems interesting .
Below is example ,where it shows How to change the text of a label from a thread:
//file1.cpp
QObject *obj = NULL; //global
QLabel *label = new QLabel("test");
obj = label; //Keep this as global and assign this once in constructor.
Next in your WorkerThread you can do as below:
//file2.cpp (ie.,thread)
extern QObject *obj;
void workerThread::run()
{
for(int i = 0; i<10 ;i++
{
QMetaObject::invokeMethod(obj, "setText",
Q_ARG(QString,QString::number(i)));
}
emit finished();
}
you start thread passing some pointer to thread function (in posix the thread function have the signature void* (thread_func)(void*), something equal under windows too) - and you are completely free to send the pointer to your own data (struct or something) and use this from the thread function (casting pointer to proper type). well, memory management should be though out (so you neither leak memory nor use already freed memory from the thread), but this is a different issue

what is the correct way to implement a QThread... (example please...)

The Qt documentation for QThread says to create a class from QThread, and to implement the run method.
Below is taken from the 4.7 Qthread documentation...
To create your own threads, subclass QThread and reimplement run(). For example:
class MyThread : public QThread
{
public:
void run();
};
void MyThread::run()
{
QTcpSocket socket;
// connect QTcpSocket's signals somewhere meaningful
...
socket.connectToHost(hostName, portNumber);
exec();
}
So in every single thread I've created, I've done just that and for most things it works just fine (I do not implement moveToThread(this) in any of my objects and it works great).
I hit a snag last week (managed to get through it by working around where I created my objects) and found the following blog post. Here is basically says that subclassing QThread really isn't the correct way to do it (and that the documentation is incorrect).
This is coming from a Qt developer so at first glance I was interested and upon further reflection, agree with him. Following OO principles, you really only want to subclass a class to further enhance that class... not to just use the classes methods directly... thats why you instantiate...
Lets say I wanted to move a custom QObject class to a thread... what would be the 'correct' way of doing it? In that blog post, he 'says' he has an example somewhere... but if someone could further explain it to me it'd be greatly appreciated!
Update:
Since this question gets so much attention, here is a copy and paste of the 4.8 documentation with the 'proper' way to implement a QThread.
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 &);
};
I still believe that it is worthwhile to point out that they include an extra Worker::workerThread member that is unnecessary and is never used in their example. Remove that piece and it is a proper example of how to do threading in Qt.
About the only thing I can think of to add is to further state that QObjects have an affinity with a single thread. This is usually the thread that creates the QObject. So if you create a QObject in the app's main thread and want to use it in another thread, you need to use moveToThread() to change the affinity.
This saves having to subclass QThread and creating your objects in the run() method, thus keeping your stuff nicely encapsulated.
That blog post does include a link to an example. It is pretty short but it shows the basic idea. Create your QObjects, connect your signals, create your QThread, move your QObjects to the QThread and start the thread. The signal/slot mechanisms will ensure that thread boundaries are crossed properly and safely.
You may have to introduce synchronization if you have to call methods on your object outside of that mechanism.
I know Qt has some other nice threading facilities beyond threads that are probably worth getting familiar with but I have yet to do so :)
Here's one example of how to use QThread correctly, but it has some issues with it, which are reflected in the comments. In particular, since the order in which the slots are executed isn't strictly defined, it could lead to various problems. The comment posted on August 6, 2013 gives a nice idea how to deal with this issue. I use something like that in my program, and here's some example code to clarify.
The basic idea is the same: I create a QThread instance that lives in my main thread, a worker class instance that lives in the new thread I created, and then I connect all the signals.
void ChildProcesses::start()
{
QThread *childrenWatcherThread = new QThread();
ChildrenWatcher *childrenWatcher = new ChildrenWatcher();
childrenWatcher->moveToThread(childrenWatcherThread);
// These three signals carry the "outcome" of the worker job.
connect(childrenWatcher, SIGNAL(exited(int, int)),
SLOT(onChildExited(int, int)));
connect(childrenWatcher, SIGNAL(signalled(int, int)),
SLOT(onChildSignalled(int, int)));
connect(childrenWatcher, SIGNAL(stateChanged(int)),
SLOT(onChildStateChanged(int)));
// Make the watcher watch when the thread starts:
connect(childrenWatcherThread, SIGNAL(started()),
childrenWatcher, SLOT(watch()));
// Make the watcher set its 'stop' flag when we're done.
// This is performed while the watch() method is still running,
// so we need to execute it concurrently from this thread,
// hence the Qt::DirectConnection. The stop() method is thread-safe
// (uses a mutex to set the flag).
connect(this, SIGNAL(stopped()),
childrenWatcher, SLOT(stop()), Qt::DirectConnection);
// Make the thread quit when the watcher self-destructs:
connect(childrenWatcher, SIGNAL(destroyed()),
childrenWatcherThread, SLOT(quit()));
// Make the thread self-destruct when it finishes,
// or rather, make the main thread delete it:
connect(childrenWatcherThread, SIGNAL(finished()),
childrenWatcherThread, SLOT(deleteLater()));
childrenWatcherThread->start();
}
Some background:
The ChildProcesses class is a child process manager that starts new child processes with spawn() calls, keeps the list of the processes currently running and so on. However, it needs to keep track of the children states, which means using waitpid() call on Linux or WaitForMultipleObjects on Windows. I used to call these in non-blocking mode using a timer, but now I want more prompt reaction, which means blocking mode. That's where the thread comes in.
The ChildrenWatcher class is defined as follows:
class ChildrenWatcher: public QObject {
Q_OBJECT
private:
QMutex mutex;
bool stopped;
bool isStopped();
public:
ChildrenWatcher();
public slots:
/// This is the method which runs in the thread.
void watch();
/// Sets the stop flag.
void stop();
signals:
/// A child process exited normally.
void exited(int ospid, int code);
/// A child process crashed (Unix only).
void signalled(int ospid, int signal);
/// Something happened to a child (Unix only).
void stateChanged(int ospid);
};
Here how it works. When all this stuff is started, the ChildProcess::start() method is called (see above). It creates a new QThread and a new ChildrenWatcher, which is then moved to the new thread. Then I connect three signals which inform my manager about the fate of its child processes (exited/signalled/god-knows-what-happened). Then starts the main fun.
I connect QThread::started() to the ChildrenWatcher::watch() method so it is started as soon as the thread is ready. Since the watcher lives in the new thread, that's where the watch() method is executed (queued connection is used to call the slot).
Then I connect the ChildProcesses::stopped() signal to the ChildrenWatcher::stop() slot using Qt::DirectConnection because I need to do it asynchronously. This is needed so my thread stops when the ChildProcesses manager is no longer needed. The stop() method looks like this:
void ChildrenWatcher::stop()
{
mutex.lock();
stopped = true;
mutex.unlock();
}
And then ChildrenWatcher::watch():
void ChildrenWatcher::watch()
{
while (!isStopped()) {
// Blocking waitpid() call here.
// Maybe emit one of the three informational signals here too.
}
// Self-destruct now!
deleteLater();
}
Oh, and the isStopped() method is just a convenient way to use a mutex in the while() condition:
bool ChildrenWatcher::isStopped()
{
bool stopped;
mutex.lock();
stopped = this->stopped;
mutex.unlock();
return stopped;
}
So what happens here is that I set the stopped flag when I need to finish, and then the next time isStopped() is called it returns false and the thread ends.
So what happens when the watch() loop ends? It calls deleteLater() so the object self-destructs as soon as control is returned to the thread event loop which happens just right after the deleteLater() call (when watch() returns). Going back to ChildProcesses::start(), you can see that there is a connection from the destroyed() signal of the watcher to the quit() slot of the thread. This means that the thread automatically finishes when the watcher is done. And when it's finished, it self-destructs too because its own finished() signal is connected to its deleteLater() slot.
This is pretty much the same idea as Maya posted, but because I use the self-destruct idiom, I don't need to depend on the sequence in which the slots are called. It's always self-destruct first, stop thread later, then it self-destructs too. I could define a finished() signal in the worker, and then connect it to its own deleteLater(), but that would only mean one connection more. Since I don't need a finished() signal for any other purpose, I chose to just call deleteLater() from the worker itself.
Maya also mentions that you shouldn't allocate new QObjects in the worker's constructor because they won't live in the thread you move the worker to. I'd say do it anyway because that's the way OOP works. Just make sure all those QObjects are children of the worker (that is, use the QObject(QObject*) constructor) - moveToThread() moves all the children along with the object being moved. If you really need to have QObjects that aren't children of your object, then override moveToThread() in your worker so it moves all the necessary stuff too.
Not to detract from #sergey-tachenov's excellent answer, but in Qt5 you can stop using SIGNAL and SLOT, simplify your code and have the advantage of compile time checking:
void ChildProcesses::start()
{
QThread *childrenWatcherThread = new QThread();
ChildrenWatcher *childrenWatcher = new ChildrenWatcher();
childrenWatcher->moveToThread(childrenWatcherThread);
// These three signals carry the "outcome" of the worker job.
connect(childrenWatcher, ChildrenWatcher::exited,
ChildProcesses::onChildExited);
connect(childrenWatcher, ChildrenWatcher::signalled,
ChildProcesses::onChildSignalled);
connect(childrenWatcher, ChildrenWatcher::stateChanged,
ChildProcesses::onChildStateChanged);
// Make the watcher watch when the thread starts:
connect(childrenWatcherThread, QThread::started,
childrenWatcher, ChildrenWatcher::watch);
// Make the watcher set its 'stop' flag when we're done.
// This is performed while the watch() method is still running,
// so we need to execute it concurrently from this thread,
// hence the Qt::DirectConnection. The stop() method is thread-safe
// (uses a mutex to set the flag).
connect(this, ChildProcesses::stopped,
childrenWatcher, ChildrenWatcher::stop, Qt::DirectConnection);
// Make the thread quit when the watcher self-destructs:
connect(childrenWatcher, ChildrenWatcher::destroyed,
childrenWatcherThread, QThread::quit);
// Make the thread self-destruct when it finishes,
// or rather, make the main thread delete it:
connect(childrenWatcherThread, QThread::finished,
childrenWatcherThread, QThread::deleteLater);
childrenWatcherThread->start();
}
subclassing the qthread class will still run the code in the originating thread. I wanted to run a udp listener in application which is already using the GUI Thread(the main thread) and while my udp listener was working perfectly my GUI was frozen as it was blocked by the subclassed qthread event handlers. I think what g19fanatic posted is correct but you will also need the worker thread to succesfully migrate the object to the new thread. I found this post which describes in details of the Do's and Dont's of the threading in QT.
Must Read before you decide to subclass QThread !
My version of best-practice thread model in Qt5 is as simple as this:
worker.h:
/*
* This is a simple, safe and best-practice way to demonstrate how to use threads in Qt5.
* Copyright (C) 2019 Iman Ahmadvand
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* It is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _WORKER_H
#define _WORKER_H
#include <QtCore/qobject.h>
#include <QtCore/qbytearray.h>
#include <QtCore/qthread.h>
#include <QtGui/qevent.h>
namespace concurrent {
class EventPrivate;
class Event : public QEvent {
public:
enum {
EventType1 = User + 1
};
explicit Event(QEvent::Type);
Event(QEvent::Type, const QByteArray&);
void setData(const QByteArray&);
QByteArray data() const;
protected:
EventPrivate* d;
};
class WorkerPrivate;
/* A worker class to manage one-call and permanent tasks using QThread object */
class Worker : public QObject {
Q_OBJECT
public:
Worker(QThread*);
~Worker();
protected slots:
virtual void init();
protected:
bool event(QEvent*) override;
protected:
WorkerPrivate* d;
signals:
/* this signals is used for one call type worker */
void finished(bool success);
};
} // namespace concurrent
#endif // !_WORKER_H
worker.cpp:
/*
* This is a simple, safe and best-practice way to demonstrate how to use threads in Qt5.
* Copyright (C) 2019 Iman Ahmadvand
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* It is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "worker.h"
using namespace concurrent;
class concurrent::EventPrivate {
public:
QByteArray data;
};
Event::Event(QEvent::Type t):QEvent(t), d(new EventPrivate) {
setAccepted(false);
}
Event::Event(QEvent::Type t, const QByteArray& __data) : Event(t) {
setData(__data);
}
void Event::setData(const QByteArray& __data) {
d->data = __data;
}
QByteArray Event::data() const {
return d->data;
}
class concurrent::WorkerPrivate {
public:
WorkerPrivate() {
}
};
Worker::Worker(QThread* __thread) :QObject(nullptr), d(new WorkerPrivate) {
moveToThread(__thread);
QObject::connect(__thread, &QThread::started, this, &Worker::init);
QObject::connect(this, &Worker::finished, __thread, &QThread::quit);
QObject::connect(__thread, &QThread::finished, __thread, &QThread::deleteLater);
QObject::connect(__thread, &QThread::finished, this, &Worker::deleteLater);
}
Worker::~Worker() {
/* do clean up if needed */
}
void Worker::init() {
/* this will called once for construction and initializing purpose */
}
bool Worker::event(QEvent* e) {
/* event handler */
if (e->type() == Event::EventType1) {
/* do some work with event's data and emit signals if needed */
auto ev = static_cast<Event*>(e);
ev->accept();
}
return QObject::event(e);
}
usage.cpp:
#include <QtCore/qcoreapplication.h>
#include "worker.h"
using namespace concurrent;
Worker* create(bool start) {
auto worker = new Worker(new QThread);
if (start)
worker->thread()->start();
return worker;
}
int main(int argc, char *argv[]) {
QCoreApplication app(argc, argv);
auto worker = create(true);
if (worker->thread()->isRunning()) {
auto ev = new Event(static_cast<QEvent::Type>(Event::EventType1));
qApp->postEvent(worker, ev, Qt::HighEventPriority);
}
return app.exec();
}

Resources