Confusion using Qt threads - c++

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.

Related

Does a class instance thread affinity have any impact on its data?

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.

Accessing Object members in another QThread

I have 2 Threads in a Qt5Application:
Thread A: contains a bunch of QObject derived class objects
Thread B: worker in this Thread has all the pointers to the objects in A
Thread A might be very busy at times and Thread B is only there to delegate Signals and manage some other stuff. It never writes to any of these objects, but I need to check some getter functions which return booleans from the objects in A.
in ThreadB:
if (objInThrA->isFinished()) { ... }
The isFinished() returns a boolean.
If Thread A is really busy in a function and I call these isFinished functions in Thread B, will my Thread B get stalled until Thread A is finished with its work, or will this work?
Qt signals and slots can be used between different threads. But there are two rules:
Last argument of connect() should be either Qt::QueuedConection or Qt::BlockingQueuedConnection (or defaults to Qt::AutoConnection, which is the same as Qt::QueuedConnection if objects belong to different threads). QueuedConnection means that emitter does not wait signal processing to be completed, BlockingQueuedConnection means it does.
QObject-derived classes are not suitable for passing between threads. They should be safely copied before that (see QMetaType docs).
You should never access members or directly call functions of an object which in another thread. The only safe way is to access them through signal/slot mechanism. You can have a signal in ThreadB and connect it to a slot in ThreadA which returns the value:
connect(objInThrB, SIGNAL(getFinished()), objInThrA, SLOT(isFinished()), Qt::BlockingQueuedConnection);
This way when you emit the signal in thread B like:
bool ret = getFinished();
the slot in thread A would be called when control returns to the event loop of thread A and the value would be returned. Thread B waits for the slot to be called, that's because the connection type is BlockingQueuedConnection. So be aware not to block the application main thread using this kind of blocking connection.
Ok, so I tested it myself.
In Thread B:
connect(this,SIGNAL(runWork()),objInThrA,SLOT(doWork()));
emit runWork();
QThread::sleep(2);
qDebug() << objInThrA->isFinished();
in Thread A:
qDebug() << "start A sleep";
QThread::sleep(10);
qDebug() << "end A sleep";
OUTPUT:
start A sleep
false
end A sleep
It works, however Im still unsure if I use it this way its correctly done and defined behavior.
The short answer is no.
When you run as described, you're directly calling methods from an object which is not in your thread (the object is in Thread A but you're calling one of its methods from Thread B). Directly calling a method is not something Qt has modified from standard C++, so it doesn't operate through signals, slots, or the event loop and is ignorant of your threading model. That means that if you call the method in Thread B, it runs in Thread B.
Calling methods on an object from another thread can be dangerous if you aren't careful about it because it introduces problems with concurrency. If Thread A is in the middle of updating the _mFinished data member when Thread B calls getFinished() on it, it may get a partially written value. In your specific example it happens to be that there is no "partially written" state for the boolean and you'll probably be fine.
Resolving concurrency problems is done through atomic operations on the elements which will be shared between multiple threads. Either you can use variables that are guaranteed to be atomic read and write operations, like booleans usually are, or you can use locking mechanisms to protect those variables. Mutexes and Semaphores are the most common locking mechanism and allow locking from multiple threads to limit access to the variables while they're being read and written. This is done in such a way as to avoid them being partially written with a new value when a read of the variable occurs.
I'd recommend reading up on mutexes and semaphores (generic multithreaded data structures) if you're doing work that involves more than one thread since they're critical to understanding threading in general. Additionally Qt has nice Qt wrapped versions of them that keep them simple to use and avoid some easy pitfalls in maintaining their usage (e.g. QMutexLocker).

Is locking necessary when using moveToThread

I searched this site and QT documentation, but could not find and direct answer for the following question:
Lets say I have a worker class with only one slot:
void Worker::testSlot(){
//access data and do some calculation
}
Now if this slot is connected to signal from other classes running on other thread, and if queued connection is used, is it necessary to use lock (QMutexLocker) before accessing data in worker? I think it is not needed since the testSlot() is executed in one thread always (the thread in which worker is moved), and thus it is synchronized. Even if two signals were emitted from different thread at the same time, there is no way to suspend executing the slot in half-way for the first signal and start for second signal. But I am not sure about this.
You're 100% correct.
The key bit of information is that emission of a signal connected to an object in a different thread via a queued or automatic connection results in posting a QMetaCallEvent to the target object. It doesn't directly result in any calls at all.
The event loop running in the thread where the target object resides has toy deliver the event to the object - you can verify that by properly overriding the event method and outputting a debug message when the event has the MetaCall type. Remember to call the base class's method in your reimplementation. Since the event loop runs synchronously, it executes the calls serially. Thus no additional serialization-of-access means are necessary. It doesn't matter what thread the meta call event was posted from - the thread per se is not used for the posting, and the event queue will look the same whether a number of events was posted from one thread, or multiple threads.
It is the QObject::event method that handles the QMetaCallEvent and executes the call. The call may be to a slot, an invokable method, a constructor/destructor, or a functor that is to execute in a given object's thread context.

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.

QMetaObject::invokeMethod returns true, but method is never called

I'm trying to run a method on the GUI thread using QMetaObject::invokeMethod, which returns true. But, if I use Qt::QueuedConnection my method never gets called (even if invokeMethod returns true).
This is what I'm using:
QMetaObject::invokeMethod(this, "draw_widgets", Qt::QueuedConnection)
I don't get any error messages or anything...
If I use Qt::AutoConnection or Qt::DirectConnection the method does get called, but from the same thread of course. Not from the GUI thread, which is what I need.
draw_widgets is a public slot of type void draw_widgets()
and my class inherits QObject and uses the Q_OBJECT macro as well.
I would appreciate any help on this, or on how to check why the method is not being called.
Thanks.
The "true" is telling you the message was successfully queued. That doesn't mean the queued message was ever processed...
Let us say your program has 10 threads (Thread1-Thread10). You queue a message from Thread7. Which thread will it be queued to? And when will items on this queue be processed?
The answer is that every QObject has something called Thread Affinity, and this is the thread where a queued slot will be run. The default affinity is to the thread where the object was created (but you can change it with QObject::moveToThread().)
If you want to queue something to the GUI thread, then the object specified by your this pointer should have the GUI thread's affinity. You can check this with the QObject::thread() method.
But in any case, no matter what thread you queue to... you must have some kind of message pump running on that thread. Look at for instance QThread::exec(). If your thread affinity is to the GUI then presumably this is already the case because you are running the app's exec.
(As a sidenote, direct calls to QMetaObject::invokeMethod are usually unnecessary. You can create a signal and tie it to a slot, then emit the signal in lieu of the invoke.)