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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With