Qt/C++ Change parent of worker to qthread fails - c++

In order to ease my cleanup efforts, I want to set the parent of my worker object to be the Qthread to which it is moved. (See below).
void TelnetServer::incomingConnection(qintptr socketDescriptor)
{
QThread * TelnetConnectionThread = new QThread(this);
TelnetConnection *worker = new TelnetConnection(socketDescriptor,TelnetConnectionThread);
connect(TelnetConnectionThread, SIGNAL(started()), worker, SLOT(start()));
connect(TelnetConnectionThread, SIGNAL(finished()), worker, SLOT(deleteLater()));
worker->moveToThread(TelnetConnectionThread); // Move worker into QThread
TelnetConnectionThread->start();
}
Right before the start() line, I added:
worker->setParent(TelnetConnectionThread);
but at runtime I see an error that I can't do that because the new parent is in a different thread. How can that be? In the line above I moved the worker to the new thread...so the worker should be in the same thread as the TelnetConnectionThread. Help?
I confirmed with some qDebug's and thread() that the worker does in fact get moved to the new thread!

I think you're a bit confused about QThread. The first problem is that its name is rather misleading as it's not actually a thread, but a thread controller. Next is the issue of thread affinity (the thread that an object is actually running on).
If we start in the main thread and create a new QThread, the thread controller is instantiated in the main thread: -
QThread* pThread = new QThread;
Next the thread is started: -
pThread->start();
Even though pThread is thought to be running in a different thread, its thread affinity is still the main thread, but any QObject-based class instance that gets moved to pThread will have the thread affinity of the new thread: -
QObject* pObject = new QObject;
pObject->moveToThread(pThread);
Still, pThread's thread affinity is the main thread, while pObject's thread affinity is the new thread; remember, pThread is actually a thread controller!
To set the parent of pObject to be pThread would be wrong, as they have different thread affinity. This is a problem that many people encounter when trying to inherit from QThread, rather than using it as a separate entity and moving QObjects to it. What usually happens is that objects are sometimes created in the constructor of their inherited QThread class, without parenting them and not realising that those objects will have the thread affinity of the main thread, not the new thread as they expect.
Moving a QObject to another thread also moves its children, so trying to set the parent as the thread (thread controller!) does not make sense.
To summarise, you cannot set the parent of your worker object to be the TelnetConnectionThread, as they run on different threads.
However, if you're trying to have the thread cleanup after itself when finished, you can do this: -
connect(TelnetConnectionThread, SIGNAL(finished()), TelnetConnectionThread, SLOT(deleteLater()));

Related

Executing two thread in parallel with one thread containing an event

I have two functions which has to be executed after specific interval of time. So I create two threads and each function is executed in separate threads. One of the function "checkForEvent()" has a Event which is waiting for an event to happen.
When the "checkForEvent()" function is waiting for an event the other function "checkServer()" is not being executed even though it is run in a separate thread.
dongleThread = new QThread(this);
checkDongle = new QTimer();
checkDongle->setInterval(DONGLE_CHECK_TIMER);
checkDongle->moveToThread(dongleThread);
connect(checkDongle, SIGNAL(timeout()), this, SLOT(checkForEvent()));
connect(dongleThread, SIGNAL(started()), checkDongle, SLOT(start()));
dongleThread->start();
serverThread = new QThread(this);
checkServer = new QTimer();
checkServer->setInterval(SERVER_CHECK_TIMER);
checkServer->moveToThread(serverThread);
connect(checkServer, SIGNAL(timeout()), this, SLOT(checkServer()));
connect(serverThread, SIGNAL(started()), checkServer, SLOT(start()));
serverThread->start();
checkForEvent() //This function is waiting for an Event
checkServer()
How can I execute both the functions in separate threads ?
Thank you!!
Your connect call uses the default connection type: Qt::AutoConnection. Here is what this means:
Qt::AutoConnection: If the receiver lives in the thread that emits the signal, Qt::DirectConnection is used. Otherwise, Qt::QueuedConnection is used. The connection type is determined when the signal is emitted.
Here your QTimer and this are in a different thread. It means Qt::QueuedConnection will be used.
Qt::QueuedConnection: The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread.
So your two slots are called in the thread of this. If one is blocking, the other one will never run.
One way of fixing the problem is having a worker object moved to its own thread. The worker object would call checkForEvent and emit a signal after the wait is over. This signal can be connected to checkServer in this. With this, you need only one thread. You can look at the documentation of QThread for more information about worker objects.

Multi-threads cause the runtime error in Qt

When I am trying to do multi-threads in Qt, for example:
If I create a class object in another class like this:
QThread thread;
Worker worker;
worker.moveToThread(thread);
it will cause the runtime error when I close the program.
But if I create the class object by pointer like this:
QThread* thread = new QThread;
Worker* worker = new Worker();
worker->moveToThread(thread);
it will be no error. Why do I have to do like this?
And do I have to delete the pointer after using? If I do not, will that cause the memory leak? I see a lot of tutorials delete them like this:
connect(worker, SIGNAL (finished()), thread, SLOT (quit()));
connect(worker, SIGNAL (finished()), worker, SLOT (deleteLater()));
connect(thread, SIGNAL (finished()), thread, SLOT (deleteLater()));
Qt typically manages the memory of its objects. Lots of the documentation says this, but not all of it.
Your runtime error is caused by a double-delete. In the first example, when worker goes out of scope it will be destructed, and Qt will also attempt to delete it. In the second example, only Qt deletes it, and you do not.
If you look towards Qt's own documentation of this, you can see them doing the same thing:
Controller() {
Worker *worker = new Worker;
worker->moveToThread(&workerThread);
...
} // notice worker was not cleaned up here, which implies moveToThread takes ownership
However, moveToThread's documentation isn't clear on this.

How to manage QThread in Qt c++?

I am trying to learn QThread in Qt. I wrote following code for QThread which is working quite good.
QThread* mThread = new QThread;
FaceCutThread* mFaceCut = new FaceCutThread();
mFaceCut->moveToThread(mThread);
connect(mThread, SIGNAL(finished()), mFaceCut, SLOT(deleteLater()));
connect(this, SIGNAL(operateFaceCut(std::string)), mFaceCut, SLOT(processFaceCut(std::string)));
connect(mFaceCut, SIGNAL(isFinisedFaceCut(QImage,bool)), this, SLOT(handleFaceCutResults(QImage,bool)));
mThread->start();
Now I want to add one more class which should work as a QThread, like;
Enroll *mEnroll = new Enroll();
Should I use mEnroll object with previous mThread or should I create new mThread2;
QThread* mThread2 = new QThread;
mEnroll->moveToThread(mThread2);
What's the advantages and disadvantages?
It depends what do you want to achieve. If you put the same classes in the same thread then they will be executed in the same thread. If you want them to be executed in separate threads then put to another thread. For example if you want to use them independently - one thread loading/reading data, second processing data and connecting them via signals. Separate threads creates problem with synchronization if threads shares resources etc. ( long topic http://www.drdobbs.com/tools/avoiding-classic-threading-problems/231000499 ) Having objects in the same thread means that objects have common
Register state (including PC and stack pointer)
Stack
Signal mask
Priority
Thread-private storage
And this can be treated as advantage or disadvantage ...

QTimer not firing in a thread

I have an Qt5 c++ app with 2 threads, thread A is started when the main program starts up. The start method of thread A runs successfully.
So far so good. Next, in the main program I send a signal to Thread A to start a QTimer, which it does - but that timer never expires!
Thread B handles tcp connections. When I initiate a telnet connection to my app, thread B fires up and suddenly I see my Qtimer from thread A expiring at normal intervals.
Why is the QTimer from thread A not expiring until thread B starts?
I suspect my threads are getting messed up. note the last section of code below products this:
thread of this: QThread(0x200fe00)
thread of timer: QThread(0x1fff470)
Which suggest my worker object (this), is in a different thread from my timer object. This timer thread address is actually the MAIN thread. Why? I'm confused.
Suggestions?
In my main app I create and start my thread like this:
QThread * MyControllerThread = new QThread(this);
if (MyControllerThread) {
TheController *worker = new TheController(MyControllerThread);
if (worker) {
connect(MyControllerThread, SIGNAL(started()), worker, SLOT(start()));
connect(MyControllerThread, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(MyControllerThread, SIGNAL(finished()), MyControllerThread, SLOT(deleteLater()));
worker->moveToThread(MyControllerThread);
MyControllerThread->start();
}
and in my main app I emit a signal to the new thread:
emit sig_startlocalpeer(Types::EActionLocalServiceStart); // Move the local peer to standby mode to start remote tests
which runs a slot in my thread (TheController object):
connect(&m_remotetestintervaltimer,SIGNAL(timeout()),this,SLOT(expiredRemoteTestIntervalTimer()));
m_remotetestintervaltimer.setTimerType(Qt::VeryCoarseTimer);
m_remotetestintervaltimer.start(REMOTETEST_TIMER_INTERVAL); // Wait between ticks
qDebug() << "thread of this: " << this->thread();
qDebug() << "thread of timer: " << m_remotetestintervaltimer.thread();
Well, it's not a Qt5 bug, it's more an inaccurate understanding of Qt's thread spirit.
In Qt, you have two ways to implement a thread which are using or not an even loop. Here is just a small visual example.
No event loop
myMethodCalledInANewThread
{
do{ ... }while(...);
}
With an event loop
myMethodCalledInANewThread
{
[...]
exec();
}
(Of course you can mix a do/while with an even loop but stay simple).
In QTimer's doc, you can read:
In multithreaded applications, you can use QTimer in any thread that
has an event loop. [...] 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.
So I'm pretty sure you don't have a second event loop in your second thread and that's why you have the behaviour you described.
To give you some tips to be totally clear with thread using Qt, I suggest you to read:
QThread doc: https://doc.qt.io/qt-5/qthread.html
QTimer doc: https://doc.qt.io/qt-5/qtimer.html
and a very good article about how QThread implementation is misunderstood by a lot of users:
You're doing it wrong: https://www.qt.io/blog/2010/06/17/youre-doing-it-wrong
I hope it will help ;)
The best answer seems to be a combination of RobbieE and Kuba:
You have to explicitly set the parent of the member variable in constructor. The parent-child feature is a Qt thing that exists among classes derived from QObject, it is not a feature of C++.
I never knew this - I assumed that when an object was created, its members variables automatically had their parent set to the object. Good to know!!

Qt C++ how stop thread if moveToThread

After lots of experimentation and learning from stackoverflow, I've create a QObject worker, a QThread, and moved my QObject worker to my QThread, and started the QThread - and it's working!
void TelnetServer::incomingConnection(qintptr socketDescriptor)
{
QThread * TelnetConnectionThread = new QThread(this);
TelnetConnection *worker = new TelnetConnection(socketDescriptor,TelnetConnectionThread);
connect(TelnetConnectionThread, SIGNAL(started()), worker, SLOT(start()));
connect(TelnetConnectionThread, SIGNAL(finished()), worker, SLOT(deleteLater()));
worker->moveToThread(TelnetConnectionThread);
TelnetConnectionThread->start(); // Start the thread running
}
I assume that calling TelnetConnectionThread->start() starts the eventloop within the QThread (since it seems to be running). Now the problem...how do I stop the thread? I tried:
QThread::quit();
but the thread is still running when I shutdown the app. Does this mean the exec loop is not running? Do I have to do something else to stop this thread? Or is it actually stopped but just not deleted?
It's a bad idea to kill running thread, from design and technical points of view.
Usually the thread must own the decision to quit based on "terminate" flag. For example create new flag "stop", if quit() slot is signaled mark the flag true. In a thread function verify the flag periodically and if it's true - exit thread function.