Pause a QThread - multithreading

UpdateThread is-a QThread That sets up a QTimer in UpdateThread::run() that calls slot UpdateThread::tick() every t ms. Now based upon some condition I need to Pause the Thread and after some time based upon another condition I need to wake it up.
Is the Way I am doing the QTimer thing is Okay ? or I should move the tick code to run and call the QThread::start() every t ms ?
How can I Pause and wake up the threads conditionally
Or I should just stop() the QTimer and start() it latter ?

First of all, you shouldn't define slots on your QThread subclass and call them from within run() - the slots will be executed (by performing a cross-thread slot invocation) in the context of the thread that owns your UpdateThread instance (the same one that created it, unless you called moveToThread() on it), not in the context of the thread represented by UpdateThread. Remember this mnemonic:
In run(), QThread::thread() != this
Instead, define the slots on a QObject subclass that you create inside run().
Ok, with that out of the way, let's have a look at the timer. The QTimer documentation contains the following:
In multithreaded applications, you can use QTimer in any thread that has an event loop.
To start an event loop from a non-GUI thread, use QThread::exec(). Qt uses the timer's
thread affinity to determine which thread will emit the timeout() signal.
Because of this, you must start and stop the timer in its thread; it is not possible to
start a timer from another thread.
(emphasis mine) Take particular note of the last sentence.
The solution is to do a cross-thread call of QTimer::start() and QTimer::stop(). You might know about cross-thread signal/slot connections. This uses the same underlying mechanism, which is exposed in QMetaObject::invokeMethod():
class UpdateThread : public QThread {
Q_OBJECT
private:
QObject * m_timer; // just a QObject* so we're not tempted
// to call functions on it
QMutext m_mutex; // protects 'm_timer'
public:
explicit UpdateThread( QObject * parent=0 )
: QThread( parent ), m_timer( 0 ) {}
// ...
private:
/* reimpl */ void run() {
QTimer timer;
// ...'timer' setup code goes here...
{
const QMutexLocker locker( &m_mutex );
m_timer = &timer; // publish 'timer' through 'm_timer'
}
// main code of run()
exec(); // start event loop so we get timer's timeout()s
// and we can receive cross-thread method calls
{
const QMutexLocker locker( &m_mutex );
m_timer = 0; // un-publish before we delete `timer`
}
}
public Q_SLOTS:
void startTimer() {
const QMutexLocker locker( &m_mutex );
if ( !m_timer ) return;
// perform cross-thread method call:
QMetaObject::invokeMethod( m_timer, "start", Qt::QueuedConnection );
}
void stopTimer() {
const QMutexLocker locker( &m_mutex );
if ( !m_timer ) return;
// perform cross-thread method call:
QMetaObject::invokeMethod( m_timer, "stop", Qt::QueuedConnection );
}
};
Now, this is how you start/stop the timer from the GUI thread. But you were also asking about alternatives.
Move tick() code into run(), call UpdateThread::start() every t milliseconds.
This is suboptimal, as it would create and destroy threads every t ms. Thread creation is still an expensive operation. Also, if UpdateThread::run() isn't done by the time you next call start(), you'll lose timer ticks.
UpdateThread as outlined above.
This isn't too bad, but it's not idiomatic multithreading, I'd say. It's a good solution if the timer fires so often that that alone would slow down the GUI thread somehow, though you might lose timer ticks this way, too.
QThreadPool
My favourite. Move the code that performs tick() into an implementation of QRunnable::run(), and queue a new runnable on a thread pool whenever the timer fires. In this case, the timer would most naturally live in the GUI thread, avoiding the need for cross-thead method calls as outlined above. Unless the GUI thread itself is overloaded, you won't miss any timer ticks. You also get for free scaling to the number of cores in the system (if you don't want that, don't use QThreadPool::globalInstance() but create your own instance and call setMaxThreadCount(1)).

Related

Groovy calling CountDownLatch.await() lead to hang

I'm new to groovy and have this simple code snippet:
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
CountDownLatch called = new CountDownLatch(1)
Timer timer = new Timer()
timer.schedule(new TimerTask() {
void run() {
called.countDown()
}
}, 0)
assert called.await(2, TimeUnit.SECONDS)
Upon running on command line, it just hang there, nothing happen. I expect that this program should quit at once. So where did I get wrong?
Actually, it's not await that leads to hanging in your case. It's just the Timer's thread is not a daemon. The JVM cannot terminate until all remaining running threads are daemons. As Thread#setDaemon() javadoc states it:
...The Java Virtual Machine exits when the only threads running are all daemon threads.
So in your case
You can just specify that the timer's thread is a daemon
CountDownLatch called = new CountDownLatch(1)
Timer timer = new Timer(true) //true means the underlying thread is a daemon
timer.schedule(new TimerTask() {
void run() {
called.countDown()
}
}, 0)
assert called.await(2, TimeUnit.SECONDS)
println("It's not await that leads to hanging")
Or if for some reason you don't want your timer's thread to be a daemon. E.g. you want the timer to handle all the scheduled tasks before the JVM terminates. In this case you can just cancel the timer at some appropriate moment
CountDownLatch called = new CountDownLatch(1)
Timer timer = new Timer() //now the underlying thread is NOT a daemon
timer.schedule(new TimerTask() {
void run() {
called.countDown()
}
}, 0)
assert called.await(2, TimeUnit.SECONDS)
println("It's not await that leads to hanging")
timer.cancel()//now we are done. All scheduled tasks will be cancelled. However, the running one will finish its job
P.S. If you want more flexible way of scheduling you can take a look at ScheduledThreadPoolExecutor. As Timers javadoc says:
...It is effectively a more versatile replacement for the Timer/TimerTask combination, as it allows multiple service threads, accepts various time units, and doesn't require subclassing TimerTask (just implement Runnable). Configuring ScheduledThreadPoolExecutor with one thread makes it equivalent to Timer.

Qt code sequence in multithread. Is this possible?

This is objectA which subclass QThread
void run()
{
while (continue)
emit query();
}
void work(int input, bool workdone)
{
// work hard here
if (workdone) { continue = false; }
}
This is some code in main object
{
ObjectA A* = new ObjectA(this);
connect(A, SIGNAL(query()), this, SLOT(handleQuery()));
objectA.start();
}
void handleQuery()
{
A.work(interger, allJobDONE);
}
OK, I don't know how to name the question. Basically, it is just "will this code work?" If yes, how would be the code sequence?
Let me explain my question. ObjectA is a thread. It is going to query information from time to time by emitting a query signal. When the query signal is grubbed by the main code, the main code decide whether there is job so as to send the job to ObjectA by calling work() function.
If this code works, both the run() and the work() function in the same object work at the same time. Is this possible?
There are few problems:
the function ObjectA::run() blocks the event loop of the thread;
A.work() is called from the wrong thread;
it is needed to think about proper deletion of A.
Instead of blocking while loop in run() it is better to use timer. However, in that case the thread event loop should be executed (that it done in the default implementation of QThread::run(). So some other member slot should be used for that task to start, for example:
void ObjectA::doLoop()
{
emit query();
QTimer::singleShot(0, this, SLOT(doLoop()));
}
That function should be called when the thread is started, for example it can be done by connection in ObjectA constructor:
connect(this, SIGNAL(started()), this, SLOT(doLoop()));
Even better to keep private pointer QTimer* to be able to stop that timer from work() or to have some other control. Note that in that case QTimer object should be in the same thread as ObjectA.
Normally the ObjectA::work() function should be triggerd by some signal from handleQuery(). The event loop of ObjectA will catch that signal and the work() will be started in ObjectA thread.

How to run a function after a specific time

I want to as if there is any way to execute a function after a specific time in windows phone 7.? For instance, see this code in android:
mRunnable=new Runnable()
{
#Override
public void run()
{
// some work done
}
now another function
public void otherfunction()
{
mHandler.postDelayed(mRunnable,15*1000);
}
Now the work done in upper code will be executed after 15 seconds of execution of otherfunction().
And I want to know is this possible in any way in windows phone 7 also.?
Thanx to all in advance..
Although you can use the Reactive Extensions if you want, there's really no need. You can do this with a Timer:
// at class scope
private System.Threading.Timer myTimer = null;
void SomeMethod()
{
// Creates a one-shot timer that will fire after 15 seconds.
// The last parameter (-1 milliseconds) means that the timer won't fire again.
// The Run method will be executed when the timer fires.
myTimer = new Timer(() =>
{
Run();
}, null, TimeSpan.FromSeconds(15), TimeSpan.FromMilliseconds(-1));
}
Note that the Run method is executed on a thread pool thread. If you need to modify the UI, you'll have to use the Dispatcher.
This method is preferred over creating a thread that does nothing but wait. A timer uses very few system resources. Only when the timer fires is a thread created. A sleeping thread, on the other hand, takes up considerably more system resources.
You can do that by using threads:
var thread = new Thread(() =>
{
Thread.Sleep(15 * 1000);
Run();
});
thread.Start();
This way, the Run method wil be executed 15 seconds later.
No need for creating threads. This can be done much more easier using Reactive Extensions (reference Microsoft.Phone.Reactive):
Observable.Timer(TimeSpan.FromSeconds(15)).Subscribe(_=>{
//code to be executed after two seconds
});
Beware that the code will not be executed on the UI thread so you may need to use the Dispatcher.

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