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 sign
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:
run()
run()
- accessing shared data that is processed both inside a slot and inside run()
requires explicitly employing thread-safety mechanisms such as mutexes and semaphoresQThread
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).
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();
//...
}