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.
Related
I believe the following code is safe, but I have not been able to confirm it:
void someMethod(Process *process) {
emit signalWithProcess(process);
process->deleteLater();
}
I'm not sure if process still exists when the signals are called and auto or queued connections are used.
For direct connections, the code above is correct because the slots are called synchronously. AFAIK, for slots on the same thread as the object, it is also correct because deleteLater() posts a new event to the object's event loop. However, the signal events are posted earlier so they run earlier.
However, for queued connections on different threads I do not understand how it works and whether the code above is safe. My gut-feeling says yes, but I have not been able to verify it.
For example, the process object above belongs to thread A and there's a queued connection to another object on thread B. When someMethod() runs, it adds the queued signals to thread B's event loop and adds the deleteLater event to thread A's event loop.
Unless there is some way to block thread A from deleting the object while the slot is run in thread B, this seems not to be safe. Unfortunately, I have not found anything related to that in the source code or the documentation.
Similar question (but without deleteLater): Is it safe to emit signal passing QObject pointer as parameter right before the passed object is going to be destroyed?
Let class A is having only one object named as objectA and it's being on a separate thread (say "TCP"):
connect(&objectA, SIGNAL(MySignal()), &objectA, SLOT(MySlot()));
Note: I assume that Qt::AutoConnection will take care of whether it's QueuedConnection or DirectConnection. I am OK with any type, which makes it safer.
Now if B (say "Processor") & C (say "Utility") are different threads, which are invoking MySignal() with their own convenience.
In the MySlot(), some data of objectA is getting written.
Question:
Do I need mutex-locking to protect data of A a;?
OR
The MySignal() will be queued automatically and hence the MySlot() will get sequentially invoked?
Use case: Currently I am having a TCP thread which send/receive data to/from server. At times, 2 threads may send the data at same time. It's likely to run 2 threads in perfect parallel now a days due to multi-processor architecture.
If the object the slot is executed on is in a different thread than the object that does the emit, then the call is not sequential. The emit will not block. Thus if you access data that the emitting object might be writing to after the emit, you need to either synchronize that access with a mutex, or use a blocking connection (which means you're forcing sequential execution, meaning emit will block until the slot has returned.)
So, if the emit happens on a different thread, and you want it to block, use a blocking connection. If you don't want the emit to block, use a mutex to protect the data. If the emit happens on the same thread, it's going to be a blocking connection anyway.
However, if the emit happens in several threads, then you always need a mutex.
Assume those threads have been created on the main thread and since connect by default uses Qt::AutoConnection and docs say:
(Default) 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.
By the time a thread emits a signal, since sender (the code running in QThread::run()) and receiver (the thread who has created the QThread object itself) are different threads, Qt::QueuedConnection is used. That is:
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 all MySlot will be sequentially executed on the main thread.
Update
You've somewhat changed your question! In general, The following connection means: MySignal could be emitted in any threads (i.e. the thread in which you've called emit MySignal()), but MySlot is only called in the thread which objectA belongs to (i.e. thread affinity). If those threads are the same, the slot is executed synchronously.
connect(&objectA, SIGNAL(MySignal()), &objectA, SLOT(MySlot()));
Do I need mutex-locking to protect data of A a;?
In case you are accessing a's data outside of the thread in which a's event loop lives, yes you do need a lock.
There's something suspect in your design.
Normally, signals are protected, and emitted only from code running in that object's thread. A more conventional design would have objects B and C emit their own signals, and you would connect those signals to the slots of objectA.
Whilst what you have might work, it will be hard to reason about, and it's probably a good time to review your design before it becomes too tangled to understand what happens in which thread.
I'm currently trying to get my hands on boost::asio strands. Doing so, I keep reading about "invoking strand post/dispatch inside or outside a strand". Somehow I can't figure out how inside a strand differs from through a strand, and therefore can't grasp the concept of invoking a strand function outside the strand at all.
Probably there is just a small piece missing in my puzzle. Can somebody please give an example how calls to a strand can be inside or outside it?
What I think I've understood so far is that posting something through a strand would be
m_strand.post(myfunctor);
or
m_strand.wrap(myfunctor);
io_svc.post(myfunctor);
Is the latter considered a call to dispatch outside the strand (as opposed to the other being a call to post inside it)? Is there some relation between the strand's "inside realm" and the threads the strand operates on?
If being inside a strand simply meant to invoke a strand's function, then the strand class's documentation would be pointless. It states that strand::post can be invoked outside the strand... That's precisely the part I don't understand.
Even I had some trouble in understanding this concept, but became clear once I started working on libdispatch. It helped me map things with asio better.
Now lets see how to make some sense out of strand. Consider strand as a serial queue of handlers which needs to be executed.
Now, where does these handlers get executed ? Within the worker threads.
Where did these worker threads come from ? From the io_service object you passed while creating the strand.
Something like:
asio::strand s(io_serv_obj);
Now, as you must be knowing, the io_service::run can be called by a single thread or multiple threads. The threads calling the run method of the io_serv_obj are the worker threads for that strand in our case. So, it could be either single threaded or multithreaded.
Coming back to strands, when you post a handler, that handler is always enqueued in the serial queue which we talked about. The worker threads will pick up the handler from the queue one after the other.
Now, when you do a dispatch, asio does some optimization for you:
It checks whether you are calling it from inside one of the worker thread or from some other thread (maybe of some other io_service instance). When it is called outside the current execution context of the strand, thats when it is called outside the strand. So, in the outside case, the dispatch will just enqueue the handler like post when there are other handlers waiting in the queue or will call it directly when it can guarantee that it will not be called concurrently with any other handler from that queue that may be running in one of the worker threads at that moment.
UPDATE:
As noted in the comments section, inside means called within another handler i.e for eg: I posted a handler A and inside that handler, I am doing a dispatch of another handler. Now, as would be explained in #2, if there are no other handlers waiting in the strands serial queue, the dispatch handler will be called synchronously. If this condition is not met, that means, the dispatch is called from outside.
Now, if you call dispatch from outside of the strand i.e not within the current execution context, asio checks its callstack to see if any other handler present in its serial queue is running or not. If not, then it will directly call that handler synchronously. So, there is no cost of enqueueing the handler (I think no extra allocation will be done as well, not sure though).
Lets see the documentation link now:
s.dispatch(a) happens-before s.post(b), where the former is performed
outside the strand
This means that, if dispatch was called from some outside the current run OR there are other handlers already enqueued, then it needs to enqueue the handler, it just cannot call it synchronously. Since its a serial queue, a will get executed before b.
Had there been another call s.dispatch(c) along with a and b but before a and b(in the mentioned order) enqueued, then c will get executed before a and b, but in no way b can get executed before a.
Hope this clears your doubt.
For a given strand object s, running outside s implies that s.running_in_this_thread() returns false. This returns true if the calling thread is executing a handler that was submitted to the strand via post(), dispatch(), or wrap(). Otherwise, it returns false:
io_service.post(handler); // handler will run outside of strand
strand.post(handler); // handler will run inside of strand
strand.dispatch(handler); // handler will run inside of strand
io_service.post(strand.wrap(handler)); // handler will run inside of strand
Given:
a strand object s
a function object f1 that is added to strand s via s.post(), or s.dispatch() when s.running_in_this_thread() == false
a function object f2 that is added to strand s via s.post(), or s.dispatch() when s.running_in_this_thread() == false
then the strand provides a guarantee of ordering and non-concurrency, such that f1 and f2 will not be invoked concurrently. Furthermore, if the addition of f1 happens before the addition of f2, then f1 will be invoked before f2.
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.
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.)