Qt moveToThread: What resources are brought with the object? - c++

Say I have created a QObject a and it has a member QObject b. (Actually, both A and B are subclasses of QObject, and class A has a member B b.)
When b is created, its parent is 0 (default). In the code, if I never set b's parent to a, and if I call movetothread() to move a into a worker thread, will b be moved into that thread too?
If it is not moved, if I call b.init() from the worker thread (the one I moved a into) which use new operator to create another QObject that has b as a parent, then I will get the following error, right?
QObject: Cannot create children for a parent that is in a different thread

As the Qt documentation for QObject::moveToThread states: -
Changes the thread affinity for this object and its children. The object cannot be moved if it has a parent. Event processing will continue in the targetThread.
In this case, a parent is an object whose child is set either by passing the parent in the constructor or by calling setParent on the child. It is not an an object which has a pointer to another object.
In the code, if I never set b's parent to a, and if I call movetothread() to move a into a worker thread, will b be moved into that thread too?
So, no, if b's parent is not set and you call moveToThread on 'a', 'b' will still have the original thread affinity.
If it is not moved, if I call b.init() from the worker thread...
If you've moved 'a' and not 'b' to a worker thread, then you should not be calling b.init directly from the worker thread. Instead, the object in the worker thread ('a') should emit a signal for an object in the original thread to call b.init from a connected slot

will b be moved into that thread too?
No, QObject doesn't know that b is a member of a. (You didn't say whether a holds a pointer to b or whether it holds b directly, but the answer is the same in both cases.)
then I will get the following error, right?
The child of a QObject must always be created in the thread which owns the parent. I'm reluctant to say that you will definitely get an error, because the behaviour may be undefined.
See Threads and QObject.

Related

Is `moveToThread(nullptr)` a valid way to pull a QObject within the destination thread from its source thread?

Suppose if an object obj belongs to a QThread T1. Ideally being in Qhread T2's function, obj can't be 'pulled' from T1 to T2. This is mentioned in moveToThread() documentation:
Warning: This function is not thread-safe; the current thread must be same as the current thread affinity. In other words, this function can only "push" an object from the current thread to another thread, it cannot "pull" an object from any arbitrary thread to the current thread. There is one exception to this rule however: objects with no thread affinity can be "pulled" to the current thread.
This answer's point-3 suggests that actually it's a "lie-to-children". Because moveToThread(nullptr) will make an object to be movable from other threads.
Is it an idiomatic way without side-effects?
void FunctionRunningInT2 (QObject& obj) // `obj` belongs to thread `T1`
{
obj.moveToThread(nullptr); // line-1 no event processing for obj!?
obj.moveToThread(T2); // line-2 is it OK ???
}
Add-on question: What will happen if any signal is emitted on obj between line-1 and line-2?
Rephrased: In case of obj.disconnect(), it doesn't accept any signals afterwards. However, the signals pending before disconnect() are still processed. Is it true for moveToThread(nullptr) as well? Or will it discard the pending signals too?
As far as I understand, one just can't call moveToThread on an object living in a different thread. Even if the argument is nullptr, you'll end up with this messages from Qt:
QObject::moveToThread: Current thread ( ... ) is not the object's thread ( ... )
Cannot move to target thread (0x0)
and the object won't move from its thread.
A safe way to pull an object to a different thread is using a queued connection, i.e. giving the moveable object a slot like
class Moveable : public QObject
{
Q_OBJECT
public:
Moveable() : QObject(nullptr) {}
public slots:
void moveMe(QThread * destination) { moveToThread(destination); }
This way, one can use a signal in the mover object, like
class Mover : public QObject
{
Q_OBJECT
signals:
void moveIt(QThread *);
connect them
connect(&mover, &Mover::moveIt, &moveable, &Moveable::moveMe, Qt::QueuedConnection);
and, wherever needed
mover.moveIt(QThread::currentThread());
or
mover.moveIt(to_whatever_thread);
If one just doesn't want to deal with implementing signals and connecting them, can safely use something like:
QMetaObject::invokeMethod(&moveable, "moveMe", Qt::QueuedConnection, Q_ARG(QThread*, destination_thread));
again exploiting a queued connection, but directly invoking the slot.
About the add-on question. Once the object is moved to thread 0x0, as stated here:
no event processing for this object or its children can happen, as
they are no longer associated with any thread.
So, the object will stop receiving signals as well, not even from another object which has also been moved to 0x0.

Qt- What is the difference between new QThread(this) and new QThread()?

I would like to know what difference there is between new QThread(this) and new QThread() and how this would influence the behaviour of my code when using QThread.
The parent of a QThread does not make any difference on who executes what.
It is just the classic parent-child relationship in Qt, the Object-Tree, meaning the parent takes ownership of the QThread instance and will delete its child when it gets deleted.
What is important when it comes to threads in Qt is
Where do you create a QObject instance (by default the object belongs to the thread that created it)
The parent of a QObject instance (when you do a QObject::moveToThread(QThread *targetThread) all the children of the object are moved too)
Because : the slots of a QObject are executed in the thread that it belongs to.

Moving a QScopedPointer to Thread

The last weeks I read a lot about RAII and thought that I should start using smart pointers in my applications. As an example I tried to modify one of my applications. It captures frames from a webcam in a thread, performes image processing in another thread and displays the processed and unprocessed images in QT widgets. One central Object is the CCameraHandler which controls the capturing thread and image processing thread. Up to this point I used 4 plain pointers as members in this class:
CCameraCapture* m_CameraCapture;
CImageProcessor* m_ImageProcessor;
QThread* m_CameraCaptureThread;
QThread* m_ProcessingThread;
In the constructor of CCameraHandler I created the Instances using new and moved the capture object to the thread:
m_CameraCaptureThread= new QThread();
m_CameraCapture= new CCameraCapture();
//Move camera capture object to thread
m_CameraCapture->moveToThread(m_CameraCaptureThread);
That approach worked nicely. Now I wanted to a first test with QScopedPointer and tried to change m_CameraCapture to a QScopedPointer using
QScopedPointer<CCameraCapture> m_CameraCapture;
and initializing it with CameraCapture(new CCameraCapture()) in the initialization list. It compiled nicely and works as it should but when I close the application an the destructors are called I get an error from Qt:"Cannot send events to objects owned by a different thread. Current thread 5ff590. Receiver '' (of type 'CCameraCapture') was created in thread 4b7780" I guess that it has to do with the m_CameraCapture->moveToThread(m_CameraCaptureThread); where I now move a scoped pointer. Is the QScopedPointer automatically parented by CCameraCapture? So far I used
//This connections guarantees that the m_CCameraCapture and m_CameraCapture are deleted after calling QThread::exit()
QObject::connect(m_CameraCaptureThread, SIGNAL(finished()), m_CameraCaptureThread, SLOT(deleteLater()));
QObject::connect(m_CameraCaptureThread, SIGNAL(finished()), m_CameraCapture, SLOT(deleteLater()));
to delete thread an worker when camera capturing is stopped. If m_CameraCapture is now parented by CCameraHandler that might cause the problems. At the moment I am not so sure if it is a good Idea to use a SmartPointer in this case. Any Ideas what might cause this error on destruction?
Edit:
The CCameraHandler dtor looks like this (threads should be deleted before the worker):
CCameraHandler::~CCameraHandler(void)
{
//Stop grabbing and processing
emit stopGrabbing();
emit stopProcessing();
/*Wait for the capture thread to terminate. The destructor of CCamera Handler might be called on application close. Therefore it is important to wait for QThreads to terminate. Else the application might close before threads get deleted*/
m_CameraCaptureThread->exit();
m_CameraCaptureThread->wait();
//Wait for the processing thread to terminate
m_ProcessingThread->exit();
m_CameraCaptureThread->wait();
qDebug() << "CCameraHandler deleted";
}
An object that has been moved to another thread must be destructed either:
From the thread itself, or
From any thread after the thread itself has been destructed.
Caveat: QThread is not safe to be destructed before you stop it. To do that safely to a thread that merely runs an event loop, you should use the following subclass instead:
class Thread : public QThread {
using QThread::run; // final
public:
Thread(QObject * parent = 0) : QThread(parent) {}
~Thread() { quit(); wait(); }
};
Given such a class, destructed from the GUI thread, you simply need to destruct it before you destruct any objects that were moved to the thread. Of course, it's not necessary to hold such objects as pointers at all, but the code below will work whether you hold them directly or as pointers.
class Foo : public Bar {
CCameraCapture m_CameraCapture;
CImageProcessor m_ImageProcessor;
Thread m_CameraCaptureThread;
Thread m_ProcessingThread;
...
}
When the class is destructed, the following happens, in order:
~Foo() body runs (it may be empty).
Members in the ... section, if any, are destructed in reverse order of declaration.
m_ProcessingThread.~Thread runs, followed by superclass destructors (~QThread, and finally ~QObject). Any objects that were moved to that thread are now threadless.
m_CameraCaptureThread.~Thread runs, followed by superclass destructors. Any objects that were moved to that thread are now threadless.
m_ImageProcessor destructors run. As a threadless object, the destruction is safe from any thread.
m_CameraCapture destructors run. As a threadless object, the destruction is safe from any thread.
If you used QScopedPointer<...> to hold those instances, things would be exactly the same, just that every object's destruction would be wrapped in the body of ~QScopedPointer<...>.
Note that the use of even a raw pointer to hold those instances is a premature pessimization: you waste a bit of heap, and access to the instances is a bit slower due to an extra layer of indirection. Those things in isolation may not play a big role, but if there are thousands of objects all coded that way, things can add up.
Don't allocate class members in individual heap blocks unless absolutely necessary.
Problem is that you are doing some UI stuff from none UI thread.
It is hard to tell exactly where is the problem since you didn't give information what exacly CCameraCapture do.
I suspect that after capturing a frame you are setting a pixmap on label (to show frame) instead emit a signal with new frame and connect this signal with respective slot of UI element. So I think that scoped pointer and signal and slots have nothing to do with your problem, problem is that you didn't use signal slot mechanism in place where it was required.

moving an object to a different thread

My application uses a custom serialization mechanism.
Phase 1) The mechanism loads clusters of data on a separate thread, creates all appropriate objects there and so on.
Phase 2) Once they are all fully deserialized, it hands them over to the main application thread and finishes the serialization there by for example setting up connections between objects etc.
This mechanism is a new addition to my framework – before that I was deserializing everything on the main thread.
The problem I have is that some of the objects that are created during deserializatiuon are Qt objects ( a bunch of widgets basically ).
They all record the ids of a thread they were created on. And when the time comes for “phase 2”, these objects start complaing that they all don’t belong to this thread and therefore can have no signals sent etc.
So I found a method on QObject, called ‘moveToThread’. The little bugger’s not very helpful though, as it performs a check and prevents from moving objects from a different thread to the current thread ( WHY scuh a constraint, I have no clue ).
Does anyone have an idea how can I go about this? I can guarantee that the objects will only be createad on a separate thread, and from that point on they will all be living and operating on the main thread.
Thanks,
Paksas
Instances of a QObject, or any instance of subclasses of QObjects must be handled with care when it comes to multi-threading.
Take a look to this page for an introduction to the topic.
Suppose that your application consists of two threads A and B.
Suppose that thread A creates an object QObject instance.
instance is said to live in thread A. This means that:
- it can directly send and receive signals to all other objects living in thread A.
- all calls done to method of myInstance from thread A are thread-safe
Accessing instance from the other thread B, on the other hand:
- is not thread safe (you must take care of race conditions).
- Moreover signals emitted by instance and connected to slot of objects in thread B are not direct: the slot execution is deferred to a later moment by copying all the method parameters and placing everything in an event to be executed by thread B event queue.
Given this, the solution that you can exploit is the following.
SubClass is a subclass of a QObject.
class SubClass : public QObject{
Q_OBJECT
[...]
}
The thread A will run the following method to deserialize and populate memory with SubClass instances
void methodA(){ /this method is executed by thread A
QThread* threadB; //a reference to the QThread related to thread B
[...]
MyQObject* instance = someFactoryMethod();
//we push the ownership of instance from thrad A to thread B
instance->moveToThread( threadB );
//do something else
}
Notice however that this might not be sufficient if thread A needs to perform other operations on instance. In particular it might happens that thread A will trigger some singals defined in MyQObject. This is not allowed since now thread A is not the owner of instance anymore.
In this case you need to defer such operation and ask thread B to perform it. This is realized by using the QMetaObject::invokeLater method.
InvokeLater allows you to call a specific slot asking thread B to execute it.
Suppose that ClassInB is a class whose instances are used in thread B
class ClassInB : public QObject{
Q_OBJECT
public:
[...]
slots:
void complexOperation(MyQObject* o){
[...]
emitSomeSignal();
}
signals:
void someSignal();
}
after moving instance to thread B we need to execute complexOperation() on an instance of ClassInB living in thread B which, in turn, will also emit someSignal().
void methodA(){ //this method is executed by thread A
QThread* threadB; //a reference to the QThread related to thread B
ClassInB* instanceOnB; //a reference to a ClassInB instance living in thread B
[...]
MyQObject* instance = someFactoryMethod();
//we push the ownership of instance from thread A to thread B
instance->moveToThread( threadB );
//we ask thread B to perform some operation related to instance
QMetaObject::invokeLater(instanceOnB, "complexOperation", Q_ARG(MyQObject*, instance) );
}
To be able to use MyQObject* as a parameter of invokeLater we need to register it to the Meta framework. You will need to:
add Q_DECLARE_METATYPE(MyQObject*) in the .cpp defining MyQObject
call once, before using the mechanism (e.g. in the main), qRegisterMetaType<MyQObject*>();
Simply replace your function calls with QTimer::singleShot(int msec, const QObject *receiver, PointerToMemberFunction method) to run a slot in another thread, since according to documentation, it executes the slot from the target thread.
This way you don't need to bother with changing your code in any way, or wondering if your current object is in the same thread or not, etc.

QObject::deleteLater across a QThread

I'm looking for a solution to schedule the deletion of an object across threads. The docs about how deleteLater behave are not entirely clear. Can I call this function in a thread which is not the object's owner?
For example, Object X is owned by Thread A, and in Thread B I would like to have Object X deleted. As the object may be inside event processing at the moment (in Thread A) I can't safely delete it until it gets back to the message loop. If I call deleteLater from Thread B however the docs seem to indicate it will delete as soon as Thread B gets back to the message loop.
Currently I take the approach of having a signal emitted in Thread A which is attached to a slot which calls deleteLater. I'm wondering if there is perhaps an easier way to do this -- if indeed I can just call deleteLater from any thread.
Looking at the Qt 4 code and Qt 5 code, deleteLater() just invokes QCoreApplication::postEvent() which is explicitly declared thread-safe. So, it should be fine to just call it directly. As the event queue is processed in the object's owner thread, deletion will happen in thread A.
Only Qt 5 QObject documentation explicitly lists deleteLater() as thread safe. If you want to completely rely on documented behaviour in Qt 4, use postEvent().
While deleteLater() is not safe itself, you can invoke it in object's threadA with meta call:
metaObject()->invokeMethod(object, "deleteLater", Qt::QueuedConnection);
Then, it will be safe.
deleteLater() only means that the object will be deleted after all signal/slots int the current event loop (i.e. ThreadB) have been treated.
So, if no other slots need ObjectX in ThreadB, it is equivalent to a plain delete.
Whether you can delete the object or not and how it will be handled in ThreadA is up to your app logic.
If ObjectX is the main object of the thread, sending the quit() signal to ThreadA is the way to go.