Qt C++ moveToThread() - c++

I've just started working with Qt on Windows and read about moveToThread() function. Would it be ok if I write like this:
class Worker : public QObject
{
Q_OBJECT
private:
QThread* thread;
public:
void GoToThread() {
thread = new QThread();
this->moveToThread(thread);
}
void DoWork() {
//long work
}
};
Worker* w = new Worker();
w->GoToThread();
w->DoWork();
And what exactly would this code do? Would it put itself to the thread? Would I be able to call DoWork() outside?

In the example you gave, DoWork() would execute on the caller's thread.
If you want DoWork() to be done on the Worker object's thread, you should have DoWork() be a slot that can be invoked either by emitting a signal that it has been connected to or by calling QMetaObject::invokeMethod() to 'call' it.
Basically, moving a Q_OBJECT to another thread makes that Q_OBJECT use an event queue associated with that thread, so any events delivered to that object via the event queue will be handled on that thread.

That will move the QObject to the new thread and on top of what Michael Burr already said you should take a look in the documentation here because you miss at least a connect thread finished to deleteLater for your QObject (and this will cause a memory leak)

Related

QTimer running in QThread

I need a class with a timer which will do a task every 100msec, this class need to run in a thread, so I would like to combine qtimer with qthread.
I have created the following code:
class Worker : public QObject
{
Q_OBJECT
public:
void setEnabled(bool enable);
public slots:
void initialize();
private:
void doWork();
QTimer *m_timer;
}
void Worker::initialize()
{
m_timer = new QTimer(this);
connect(m_timer, &QTimer::timeout, this, &Worker::doWork, Qt::DirectConnection);
m_timer->start(100);
}
void Worker::setEnabled(bool enable)
{
if(enable)
m_timer->start(100);
else
m_timer->stop();
}
int main(int argc, char *argv[])
{
QCoreApplication app(argc,argv);
QThread *thread = new QThread;
Worker *worker = new Worker;
QObject::connect(thread, &QThread::started, worker, &Worker::initialize);
worker->moveToThread(thread);
thread->start();
app.exec();
delete worker;
delete thread;
}
With the following commands I could then enable/disable the time
worker->setEnabled(false);
worker->setEnabled(true);
I have tested and it works fine, but I would like to know if this is the correct way?
Thanks for the help
No, it's not entirely correct.
Worker::setEnabled(bool enable) should be a slot too, as it's invoking the QTimer::start() slot directly. Calling Worker::setEnabled directly from the main thread then results in undefined behavior. You must use a signal-slot connection to invoke setEnabled safely from the main thread.
You also should have initialized Worker::m_timer in the constructor rather than deferring it until initialize(), so you don't run into a dangling pointer if Worker::setEnabled was invoked earlier than expected. moveToThread will move all children of Worker with it, so that's perfectly sane behavior.
The only thing I need to mention is that the m_timer can't be initialzed in the constructor. See here information from qt:
By the way, one extremely important thing to note here is that you should NEVER allocate heap objects (using new) in the constructor of the QObject class as this allocation is then performed on the main thread and not on the new QThread instance, meaning that the newly created object is then owned by the main thread and not the QThread instance. This will make your code fail to work. Instead, allocate such resources in the main function slot such as initialize() in this case as when that is called the object will be on the new thread instance and thus it will own the resource.

Creating QNetworkAccessManager in another thread

I have a QNetworkAccessManager created in another thread.
The network is meant to be used only in MyMegaThread.
QNetworkAccessManager is created from the thread's run method:
mp_manager.reset(new QNetworkAccessManager{this});
On creation I get such a message in console:
QObject: Cannot create children for a parent that is in a different thread.
(Parent is MyMegaThread(0x237eabd0ee0), parent's thread is QThread(0x237e70742a0), current thread is MyMegaThread(0x237eabd0ee0)
This message is totally harmless, but I wonder which parent the manager is supposed to have.
I suspect it happens because the MyMegaThread instance is created in the main thread, but I need a parent created in MyMegaThread instead.
What is an idiomatic way of doing this?
Parent is MyMegaThread(0x237eabd0ee0), parent's thread is
QThread(0x237e70742a0), current thread is MyMegaThread(0x237eabd0ee0)
The issue does not relate to QNetworkAccessManager.
Here is the demo to reproduce the warning.
#include <QDebug>
#include <QThread>
class MyMegaThread : public QThread
{
Q_OBJECT
public:
using QThread::QThread;
protected:
void run() override {
qDebug()<<QThread::currentThread()<<this->thread();
new QObject(this);
}
};
// main
MyMegaThread m;
m.start();
Output:
MyMegaThread(0x60fe18) QThread(0x16a7c48)
It's rule of QObject:
All QObjects must live in the same thread as their parent.
Consequently:
setParent() will fail if the two QObjects involved live in different
threads. When a QObject is moved to another thread, all its children
will be automatically moved too. moveToThread() will fail if the
QObject has a parent. If QObjects are created within QThread::run(),
they cannot become children of the QThread object because the QThread
does not live in the thread that calls QThread::run().
http://doc.qt.io/qt-5/qobject.html#thread-affinity
Have to make sure this code new QObject running QThread be same as given parent QObject thread.
mp_manager.reset(new QNetworkAccessManager{this});
No, the message is not harmless at all. The object you have created has a null parent and no reference on the thread association and thus its thread() method may return a dangling pointer at any time. It cannot safely use timers nor receive cross-thread calls. It is basically as useless object, and you're asking for undefined behavior to strike. This shouldn't be a warning, but a failure. Qt did you a disservice here by allowing you to continue.
The idiomatic way of doing it is first of all not to derive from QThread. QThread is a thread handle. It wraps a system resource. Put all of your functionality into a regular QObject moved into a QThread. The idiomatic way to endlessly "do stuff" on any thread, including the main thread, is to use a zero-duration timer. Note that zero-duration timers have nothing to do with timing at all. They are essentially event loop handles, calling them a timer is a misnomer.
To wit:
// https://github.com/KubaO/stackoverflown/tree/master/questions/thread-simple-50632807
#include <QtNetwork>
class Thread final : public QThread {
Q_OBJECT
public:
void takeObject(QObject *obj) {
obj->moveToThread(this);
}
~Thread() override {
requestInterruption();
quit();
wait();
}
};
class Class : public QObject {
Q_OBJECT
QBasicTimer m_workTimer;
QNetworkAccessManager m_manager{this};
void doWorkChunk() {
qDebug() << "tick...";
QThread::sleep(1); // emulate a blocking operation
}
protected:
void timerEvent(QTimerEvent *ev) override {
if (ev->timerId() != m_workTimer.timerId())
return;
doWorkChunk();
}
public:
explicit Class(QObject *parent = {}) : QObject(parent) {
m_workTimer.start(0, this);
}
};
int main(int argc, char *argv[]) {
QCoreApplication app(argc, argv);
Class object;
Thread workThread;
workThread.start();
workThread.takeObject(&object);
QTimer::singleShot(3000, &QCoreApplication::quit);
return app.exec();
}
#include "main.moc"
The QBasicTimer::stop: Failed. Possibly trying to stop from a different thread warning is relatively benign and indicates an internal timer handle leak. For a workaround, see this answer.

Qt objects can still be deletedLater() without event loop?

I'm confused about threads and event loops in Qt.
A QThread normally runs exec() in run(). But when you override run(), there will not be an event loop.
This (older) doc states that calling deleteLater() on objects that are created in a thread without an event loop doesn't work:
If no event loop is running, events won't be delivered to the object.
For example, if you create a QTimer object in a thread but never call
exec(), the QTimer will never emit its timeout() signal. Calling
deleteLater() won't work either. (These restrictions apply to the main
thread as well.)
However, look at the following code:
class MyObject : public QObject
{
Q_OBJECT
QString content;
public:
MyObject(QObject *parent = 0);
~MyObject();
};
class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = 0);
void run();
signals:
public slots:
};
MyObject::MyObject(QObject *parent) :
QObject(parent),
content("foobar")
{}
MyObject::~MyObject()
{
// This code is still executed before I close the program. How?
qDebug() << "Destroying MyObject";
}
MyThread::MyThread(QObject *parent) :
QThread(parent)
{}
void MyThread::run()
{
// Creating a heap object in a thread that does not have
// an event loop (because I reimplemented run()).
MyObject * objectification = new MyObject();
sleep(1);
objectification->deleteLater();
}
So why does the deletelater() call still post an event that is picked up?
As the Qt docs state for deleteLater: -
Since Qt 4.8, if deleteLater() is called on an object that lives in a thread with no running event loop, the object will be destroyed when the thread finishes.
The object is still being deleted when no event loop exists. If you look at the source code for QObject::deleteLater, you'll see that an event is posted:-
void QObject::deleteLater()
{
QCoreApplication::postEvent(this, new QDeferredDeleteEvent());
}
So, let's look at what happens when a thread is deleted. QThreadData's destructor includes this:-
for (int i = 0; i < postEventList.size(); ++i) {
const QPostEvent &pe = postEventList.at(i);
if (pe.event) {
--pe.receiver->d_func()->postedEvents;
pe.event->posted = false;
delete pe.event;
}
}
As we see, although there's no event loop, the event list is still available.
If we look more closely into QThreadPrivate (just taking one platform as an example, in this case unix), you'll see that when the thread finishes, it forwards all deferred deleted messages, so they can continue to be processed:
QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);

QObject: Cannot create children for a parent that is in a different thread

EDIT:
I tried doing what you guys told me in comments ... :
Citizen * c = new Citizen(this);
QThread thread;
c->moveToThread(&thread);
connect(&thread, SIGNAL(started()), c, SLOT(ProcessActions()));
thread.start();
This produces even more errors:
QThread: Destroyed while thread is still running
ASSERT failure in QThread::setTerminationEnabled(): "Current thread was not started with QThread.", file c:\ndk_buildrepos\qt-desktop\src\corelib\thread\qthread_win.cpp, line 542
Invalid parameter passed to C runtime function.
Invalid parameter passed to C runtime function.
QObject::killTimers: timers cannot be stopped from another thread
I am having problems with this error ... I'm stuck on this for 2 days already and can't get a solution.
Header:
class Citizen : public QThread
{
Q_OBJECT
QNetworkAccessManager * manager;
private slots:
void onReplyFinished(QNetworkReply* net_reply);
public:
Citizen(QObject * parent);
void run();
};
Implementation:
Citizen::Citizen(QObject * parent)
{
manager = new QNetworkAccessManager;
connect(_net_acc_mgr, SIGNAL(finished(QNetworkReply*)),
this, SLOT(onReplyFinished(QNetworkReply*)));
}
void Citizen::onReplyFinished(QNetworkReply* net_reply)
{
emit onFinished(net_reply);
}
void Citizen::run()
{
manager->get(QNetworkRequest(QUrl("http://google.com"));
QEventLoop eLoop;
connect(manager, SIGNAL( finished( QNetworkReply * ) ), &eLoop, SLOT(quit()));
eLoop.exec(QEventLoop::ExcludeUserInputEvents);
qDebug() << "loaded google!";
exec();
}
When manager->get() gets executed, I get the following error:
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QNetworkAccessManager(0xc996cf8), parent's thread is QThread(0xaba48d8), current thread is Citizen(0xca7ae08)
When eLoop.exec() gets executed:
QObject::startTimer: timers cannot be started from another thread
I start this thread in the following manner:
Citizen * c = new Citizen(this);
c->start();
Why does this happen? How to solve this?
QObject: Cannot create children for a parent that is in a different thread.
You get this because you are creating the QNetworkAccessmanager in the constructor of Citizen, which is being called in the "original" thread. When the Citizen object is moved to the new thread the QNetworkAccessmanager still has its thread affinity set to the original thread but in the run call it will attempt to create the QNetworkReply object ( and probably other objects aswell ) in the new thread. Which produces the warning above.
If you create the manager in the run slot(or at any point after the Citizen object is moved to the new thread) that will not happen.
However you still have some issues. For instance, the Citizen class really doesn't need to be a QThread. It needlessly complicates it. It will suffice for your purpose(afaict) to subclass a QObject. Just make a normal slot and connect that to the QThread::started() signal. And as OrcunC pointed out you need to make sure that the QThread instance is properly scoped.
For more on threading: http://blog.qt.io/blog/2010/06/17/youre-doing-it-wrong/
Example:
QThread *thread = new QThread;
thread->start();
Citizen *worker = new Citizen;
worker->moveToThread(thread);
//startWorking can be equivalent of the run function
//in your current implementation and this is where you should
//create the QNetworkAccessManager
QMetaObject::invokeMethod(worker,"startWorking");
I will just try to answer why you are seeing QThread: Destroyed while thread is still running error.
If you do this
void mtMethod () {
Citizen * c = new Citizen(this);
QThread thread;
c->moveToThread(&thread);
connect(&thread, SIGNAL(started()), c, SLOT(ProcessActions()));
thread.start();
}
The thread object will be destroyed when you exit the function but the thread that has been started is still running !. Qt is warning you that you should either stop the thread or create the thread object in a bigger scope. (i.e make it a member function of your class). Something like this :
class myClass
{
virtual ~myClass ();
QThread mythread;
};
myClass::~myClass
{
mythread.stop ();
}
void myClass::mtMethod () {
Citizen * c = new Citizen(this);
c->moveToThread(&mythread);
connect(&mythread, SIGNAL(started()), c, SLOT(ProcessActions()));
mythread.start();
}
I don't believe the new thread exists until run is called. So the constructor is a different thread than run(). What happens if you move the creation of the manager object from the constructor to run()? I imagine that will fix the first error, if not the timer error as well.
Also, I think many people are still building threads the way you are, but you might want to check out this.
You need to consider thread affinity. That error message is not lying or insane, it's telling you exactly what's wrong.
Your problems are mostly due to trying to subclass QThread. Even though the documentation recommends it, it is not the best way to use QThread. Please see this question and answer for more information and links.
I haven't figured out the startTimers error although it could be related to the first one. In any case, you should be able to fix the first error. I have run into this problem in Qt a few times and I find this to be the "best" way to work around it is to create an initialize function and a cleanUp function. All members of the class are pointers that are initialized to NULL until run is called. Note that "best" is in quotes because there are sure to be differing opinions but it works for most situations for me.
Header
class Citizen : public QThread {
Q_OBJECT
QNetworkAccessManager * manager;
private slots:
void onReplyFinished(QNetworkReply* net_reply);
public:
Citizen(QObject * parent);
void run();
private:
void initialize();
void cleanUp();
};
Implementation
Citizen::Citizen(QObject * parent) :
manager(NULL) {
}
void Citizen::onReplyFinished(QNetworkReply* net_reply) {
emit onFinished(net_reply);
}
void Citizen::run() {
initialize();
manager->get(QNetworkRequest(QUrl("http://google.com"));
QEventLoop eLoop;
connect(manager, SIGNAL( finished( QNetworkReply * ) ),
&eLoop, SLOT(quit()));
eLoop.exec(QEventLoop::ExcludeUserInputEvents);
qDebug() << "loaded google!";
exec();
cleanUp();
}
void Citizen::initialize() {
manager = new QNetworkAccessManager;
connect(_net_acc_mgr, SIGNAL(finished(QNetworkReply*)),
this, SLOT(onReplyFinished(QNetworkReply*)));
}
void Citizen::cleanUp() {
delete manager;
disconnect(_net_acc_mgr, SIGNAL(finished(QNetworkReply*)),
this, SLOT(onReplyFinished(QNetworkReply*)));
}

Is it possible to implement polling with QThread without subclassing it?

I have a class, which is an abstraction of some device.
class Device
{
public:
...
void Start();
void Stop();
void MsgLoop();
signals:
void sMsgArrived();
}
Start() and Stop() are called from GUI thread. Start() begins new thread, which runs MsgLoop(). It looks like this:
void MsgLoop()
{
forever {
if(SUCCESS == ReadMsg()) //synchronous, non-blocking
{
ProcessMsg(); //quite fast
emit sMsgArrived(); //this signal is connected with a slot in GUI thread
}
}
}
When Stop() is called, program should return from MsgLoop() and stop the thread. How can I implement this with QThread without subclassing it?
Generally you have to decide who will be responsible for managing the thread. Is it the Device or the main window? Or possibly some device manager. In your case the Device should probably manage its own thread, so if you don't want to subclass it, use composition:
class Device : QObject
{
Q_OBJECT
public:
Device(QObject * parent = NULL);
void Start();
void Stop();
private slots:
void MsgLoop();
signals:
void sMsgArrived();
private:
QThread thread;
bool stopThread;
};
Device::Device(QObject * parent) : QObject(parent)
{
moveToThread(&thread);
connect(&thread, SIGNAL(started()), this, SLOT(MsgLoop()));
}
void Device::Start()
{
stopThread = false;
thread.start();
}
void Device::Stop()
{
stopThread = true;
thread.wait(); // if you want synchronous stop
}
void Device::MsgLoop()
{
// your loop
while(!stopThread)
if(SUCCESS == ReadMsg())
{
ProcessMsg();
emit sMsgArrived();
}
QThread::currentThread->quit();
}
NOTE: the thread stopping will only work if ReadMsg really is non-blocking. If you later decide to switch to blocking read (and that would probably be appropriate for most cases), you will have to figure out another way how to stop your thread.
If you look at this link you can see that it is possible to run a method in a separate thread without subclassing a QThread.
However what you are asking is running a message loop forever.
If you follow the given example you can run your loop without subclassing but the QThread object will never enter into its own message loop cause it will never return from your slot. So here is an example but I think it would be a bad design
class Device : public QObject
{
Q_OBJECT
public:
Device(QObject* parent = 0);
~Device();
public Q_SLOTS:
void MsgLoop();
};
QThread* thread = new QThread;
Device* device = new Device;
void Widget::onBtnStartClicked()
{
device->moveToThread(thread);
//This will call start method of Device
connect(thread, SIGNAL(started()), device, SLOT(MsgLoop()));
//This will start the event loop of thread
thread->start();
}
void Widget::onBtnStopClicked()
{
//Tells the thread to exit
thread->exit(0);
}
I am afraid you have to subclass a QThread if you want to run a forever loop.
IMHO you shouldn't. Polling requires being in a forever loop. You must do this in QThread's run function so there is no way to re-implement a function without sub-classing first. Even if you were to try and workaround it with a single shot timer I don't recommend it. You are better off(this is how i like to do it) sub-classing QThread, calling moveToThread(), not call exec() and put a forever loop in run. For an example of this look at the Fortune Blocking Client example from qt. If you don't call moveToThread() on QThread then the QThread object still resides in the GUI main thread and they both share the same event loop (which is bad when using polling functions). Calling moveToThread(QThread) without calling exec() means the QThread will not have an event loop(which is good in your case). Calling exec() would start it's own event loop but is not used for polling schemes and you would leave the run function.