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.
Related
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.
I have two objects which lives in different threads and I'm trying to figure if a pattern used is thread safe or not.
The first object is QObject-derived and lives (was created in) the main Qt thread. The class contains some Q_INVOKABLE methods that should be called from QML, some signal*() methods defined as signals: and some Emit*() (normal) methods that I use as wrappers to emit signals. For example:
void MyQObjectClass::EmitStatus(void) {
emit signalStatusChange(_status);
}
I normally listen for those signals in QML.
The second object is not QObject-derived and lives in a second thread (pthread). This thread runs its own event loop (libev) and dispatches events. I can't use anything related to Qt in this thread because I need the custom libev event loop. On this object I defined some Notify*() methods that will send async events through libev to be picked up by callbacks.
I need to be able to communicate between the two objects/threads, but I'm not sure how to safely do this.
The actual design is to let the pthread thread object call the different Emit*() methods directly so that the QObject can properly propagate the information to Qt/QML. If I need to send information from Qt/QML to the pthread/libev object I call (from the Qt thread) the Notify*() methods.
When reading Accessing QObject Subclasses from Other Threads, it says:
QObject and all of its subclasses are not thread-safe. This includes the entire event delivery system.
but then further it is stated that:
On the other hand, you can safely emit signals from your QThread::run() implementation, because signal emission is thread-safe.
So my question is, is the design described above thread-safe? Can I safely call myQObject->EmitMySignal(), which in turns will call emit signalMySignal(), all this from inside the pthread object?
I will demonstrate how to achieve what you want with events instead of signals and slots that you cannot use (because one side is not QObject derived)
class MyObjectClass : public QObject
{
Q_OBJECT
public:
virtual bool event(QEvent *event) override
{
bool result = true;
if(event->type() == QEvent::User+1)
emit signalStatusChange(_status);
else
result = QObject::event(event); //call direct parent's event here!
return result;
}
};
And in your other thread you will do this:
MyObjectClass *p; //holds pointer to the instance in main thread
qApp->postEvent(p, new QEvent(QEvent::User+1));
This will retrieve pointer to the app that lives in the main thread and post event to its event loop. The event will be processed asynchronously from the call however so the behaviour will be different than what you are doing now. But it will be safer and imho more elegant. You can add as many types as you need. Do not forget to propagate the event to the parent if you have not handled it though!
We know from the QThread documentation
A QObject instance is said to have a thread affinity, or that it lives
in a certain thread. When a QObject receives a queued signal or a
posted event, the slot or event handler will run in the thread that
the object lives in.
Does the thread affinity have any impact on the class instance data? Does the class data become thread data?
Apart from the above, the reason I am asking is because I want to pass a pointer/reference of another class in its constructor. If I am being object oriented, I shall not access its data directly but if I call a member function of the other class, will it also be called in this class's thread?
Does the thread affinity has any impact on the class data?
No, a QObject's thread affinity only controls which thread its slot and event handlers run in.
Does the class data becomes a thread data?
Class data means class static data members - that can't possibly be affected by the thread affinity of each instance. Instance data isn't somehow made thread-local either: thread-local storage can be very limited, and there's simply no reason to force every instance into it.
Apart from the above ...
If you don't issue a signal or event, normal method calls are just method calls.
First of all, I am not using a GUI. (In case that matters.) I want to send the path of a file to a thread (as char*), have it process the file, then return. Preferably, I would like the thread to stop when it's not being used.
The Qt documentation shows two approaches to creating threads:
Create a QObject and moveToThread().
Create a QThread then start() it when it's needed.
In the two approaches above, what is happening if I don't have a run() function? I don't have one because I don't see a way of passing the char* to run(), so I'm using a signal. Do I have to start() the thread in order for it to work properly? If so, what does this do if there is no run()? Can I just create it, connect the signals/slots, then call it when I need it? Does one of the above approaches offer an advantage in this case?
UPDATE: Thank you for the quick response Johannes Schaub and thuga.
If I'm using QObject->moveToThread(), that thread is then running in an event loop? And this event loop sleeps when there is no input? (If so, that's good.) The thread (event loop) is tied to QObject's signals and slots, right? So I need to then have this object's scope be the calling thread by putting it in the constructor? (And quit() wait() in the destructor) It therefore runs for the entire lifetime of the original thread?
I don't think I need to have a slot for the QThread, because I only want to invoke it, not communicate back and forth. (Except the finished signal.) So I would do something like this:
a. Create an instance of the QThread:
WorkerThread *workerThread = new WorkerThread(this);
b. Send it the string. This is the part I'm not sure about. I think Johannes tried to explain, but I'm still not clear. I can't send the filename via a signal/slot because QThreads shouldn't use slots. (but can in moveToThread() case because of queued connections)
c. Start the Thread with .start()
The default run function then calls exec, which enters an event loop. The loop sleeps if it doesnt have an event to process.
The object that you move to the thread is not the QThread object itself. It is another object. The QThread object itself just has the event loop and is still associated with the main thread (its affinity is the main thread).
If the thread operates in the background, you best use QString as the filename and then call a respective "processFile" function or similar of that object that you pass the file name. The invocation can either be by a signal slot connection or an explicit QMetaObject::invokeMethod, using the connection type QueuedConnection (which passes an event into the event loop of the thread of the object, so your file names are automagically queued by being contained in that internal slot call event).
If I'm using QObject->moveToThread(), that thread is then running in an event loop?
Those are completely unrelated. A bare QThread is running the event loop as soon as you start() it. For this to happen you don't need to move any objects to it. Of course the event loop is dormant since there are no incoming events for it to process - so the thread, in spite of having been started, doesn't consume any CPU.
The thread (event loop) is tied to QObject's signals and slots, right?
Signals and slots are simply function call sources and sinks that you can link up. They have not much to do with event loops.
When the sender and receiver objects reside in different threads, the delivery of a slot call is implemented by posting a QMetaCallEvent to the object's event queue. That even, like all events, is given to QObject::event(QEvent*) method. That method acts on the QMetaCallEvent and executes the slot call.
So I need to then have this Object's scope be the calling thread by putting it in the constructor? (And quit() wait() in the destructor) It therefore runs for the entire lifetime of the original thread?
The object's lifetime is decoupled from thread's lifetime. An object that is moved to a given thread can only be destructed from that thread. If the thread terminates first, the object becomes threadless (its thread() returns nullptr), and it can be destructed from any thread, or moved to another thread. A threadless object can't receive any events, but of course it can receive direct slot calls. Queued slot calls won't work since those are delivered as events initially, and only internally converted into calls.
I don't think I need to have a slot for the QThread, because I only want to invoke it, not communicate back and forth.
A QThread is a thread controller. There's very little reason to subclass it. In almost all cases you can either use a QObject that has been moved to the thread, or QtConcurrent::run.
So I would do something like this: [...] Create an instance of the QThread: [...] Send it the string.
You want to send the string to an object that lives in the thread, not to the thread itself.
Here's a small example:
// main.cpp
#include <QThread>
#include <QCoreApplication>
#include <QDebug>
class Worker : public QObject {
public:
Q_SLOT void say(const QString & str) { qDebug() << str; }
};
/// A thread that's safe to destruct at any time.
class Thread : public QThred {
using QThread::run;
public:
~QThread() { quit(); wait(); }
};
int main(int argc, char ** argv) {
QCoreApplication app(argc, argv);
Worker worker;
Thread thread;
thread.start();
worker.moveToThread(&thread);
// Equivalent to invoking the say slot from a signal
QMetaObject::invokeMethod(&worker, "say", Q_ARG(QString, "hello"));
//
QMetaObject::invokeMethod(&app, "quit");
return app.exec();
}
#include "main.moc"
It sounds like your thread is supposed to process a char* and then wait. If this is the case, there's a third option available to you where you have a single function that runs in a separate thread and then exits, using QtConcurrent::run()
Simple example:
void workerFunction(QString const &data){
// ...
}
void callingFunction(){
// ....
char *data = .....;
QFuture<void> future = QtConcurrent::run(workerFunction, QString(data));
}
EDIT:
If you need more features than a single threaded function but not as many as a fully-fledged subclass of QThread, there is also the QRunnable/QThreadPool pair as a convenient intermediate option.
So if I understand correctly, If I have a class FunctionsClassthat inherits QObject and i set that class up on a Qthread called FunctionClassThreadby doing:
FunctionsClass classObj;
classObj.moveToThread( &FunctionClassThread );
FunctionClassThread.start();
From what I understand this method of setting up a thread will only handle the execution of slots in the FunctionsClass, which means the thread running FunctionsClass can be blocked if a slot in FunctionsClass for some reason has a infinite loop.
So my questions are: How can I run the functions of FunctionsClass on a thread not just the slots? Is there a way to place a whole object (functions, member variables, etc) on a thread for execution of code/data from that whole object only? And is my understanding of how the thread will handle the execution of slots correct?
When you execute a method of an object it is executed in the thread you're invoking the method. It doesn't matter where the QObject is living.
If you want to invoke a method so that it is executed in another thread asynchronously you'll have to handle the situation so that the message is posted, waits for the thread to be available (might be busy, it has to return control to the event loop first) and then, run the method.
This can be done using signals and slots, with the usual connection. If you don't want to use that mechanism, you can use QMetaObject, but you still have to declare those as slots. The static method invokeMethod, if called with Qt::QueuedConnection will invoke the method in the thread in which the object owning the method is living. You can also pass arguments to the method and returns values from it.
Consider that any data types you want to be able to pass from a thread to another need to be registered with qRegisterMetaType and must respect the conditions reported in there.
Methods of a class will execute in the context of the thread that calls them. If you move a QObject class to a thread (let's refer to it as worker thread), then only methods of that class that are called directly (or indirectly) from the run() method of the worker thread, will execute in the context of the worker thread.
If you want to call methods on that class from some other thread, but still have them run in the context of the worker thread, then you need some way to get a message to the worker thread so it can call the method you want. This is essentially what is achieved by Qt signals and slots when thread boundaries are crossed.
With a lot of extra work, there are two other ways you can do the same thing. First, QThreads have an event loop which is started by default if you don't override run(). You can create custom events that you can post to the event loop which can trigger activity in your class that will execute in the context of the worker thread.
The second way would be to call methods in your class from another thread that modify class fields that the worker thread monitors. You need to be sure that access to any of these fields is synchronized with some mechanism like a mutex.