In ObjC with GCD, there is a way of executing a lambda in any of the threads that spin an event loop. For example:
dispatch_sync(dispatch_get_main_queue(), ^{ /* do sth */ });
or:
dispatch_async(dispatch_get_main_queue(), ^{ /* do sth */ });
It executes something (equivalent to []{ /* do sth */ }
in C++) in the main thread's queue, either blocking or asynchronously.
How can I do the same in Qt?
From what I have read, I guess the solution would be somehow to send a signal to some object of the main thread. But what object? Just QApplication::instance()
? (That is the only object living in the main thread at that point.) And what signal?
From the current answers and my current research, it really seems that I need some dummy object to sit in the main thread with some slot which just waits to get in some code to execute.
So, I decided to subclass QApplication
to add that. My current code, which doesn't work (but maybe you can help):
#include <QApplication>
#include <QThread>
#include <QMetaMethod>
#include <functional>
#include <assert.h>
class App : public QApplication
{
Q_OBJECT
public:
App();
signals:
public slots:
void genericExec(std::function<void(void)> func) {
func();
}
private:
// cache this
QMetaMethod genericExec_method;
public:
void invokeGenericExec(std::function<void(void)> func, Qt::ConnectionType connType) {
if(!genericExec_method) {
QByteArray normalizedSignature = QMetaObject::normalizedSignature("genericExec(std::function<void(void)>)");
int methodIndex = this->metaObject()->indexOfSlot(normalizedSignature);
assert(methodIndex >= 0);
genericExec_method = this->metaObject()->method(methodIndex);
}
genericExec_method.invoke(this, connType, Q_ARG(std::function<void(void)>, func));
}
};
static inline
void execInMainThread_sync(std::function<void(void)> func) {
if(qApp->thread() == QThread::currentThread())
func();
else {
((App*) qApp)->invokeGenericExec(func, Qt::BlockingQueuedConnection);
}
}
static inline
void execInMainThread_async(std::function<void(void)> func) {
((App*) qApp)->invokeGenericExec(func, Qt::QueuedConnection);
}
May something like this be any useful?
This piece of code will make your lambda run on the main thread event loop as soon as it is possible. No args support, this is a very basic code.
NOTE: I didn't test it properly.
I have absolutely no idea what your talking about, but I'm going to try to answer it any way.
Lets say your have a class with a slot fucntion
So no if you want to run this synchronously in the main thread you can call that function directly. In order to connect a signal you need to create an object and connect a signal to the slot.
And somwhere in the main thread you do something like
So now if something you can connect multiple signals to that slot object, but realisticly the code I provided won't run any different than a normal function call. You'll be able to see that with a stack trace. If you add the flag qobject::queuedConneciton to the connect then it will que the slot call in the event loop.
You can easily thread a signal as well, but this will automatically be a queuedConnection
Now you'll have a threaded signal basically. If your signal is going to be threaded then all you have to do is switch to signalClass.moveToThread(&someThread), when the signal is emitted signalClass will be run in the main thread.
If you don't want an object to be called, I'm not sure, lamdas might work. I've used them before but Ithink they still need to be wrapped up in a class.
Although I'm pretty sure with Qt5 you can even go as far as creating a slot in line within a connect. But once your using lambdas I have no idea how threads work with them. As far as I know you need an object to sit in a thread basically to force calling the slot from the main thread.
There are one new approach that is the easiest I think. It`s from Qt 5.4. Link to documentation
Example:
lambda will be executed in qApp thread(main thread). You could replace context with any QObject you want.
Updated
QTimer needs event loop to work. For Threads with no qt event loop(std::thread) we could create one. Code to run lambda in std::thread.
Full example
It is certainly possible. Any solution will center on delivering an event that wraps the functor to a consumer object residing in the desired thread. We shall call this operation metacall posting. The particulars can be executed in several ways.
Qt 5.10 & up TL;DR
TL;DR for functors
TL;DR for methods/slots
TL;DR: What about a single shot timer?
All of the above methods work from threads that don't have an event loop. Due to QTBUG-66458, the handy appropriation of
QTimer::singleShot
needs an event loop in the source thread as well. ThenpostToObject
becomes very simple, and you could possibly just useQTimer::singleShot
directly, although it's an awkward name that hides the intent from those unfamiliar with this idiom. The indirection via a function named to better indicate the intent makes sense, even if you don't need the type check:Common Code
Let's define our problem in terms of the following common code. The simplest solutions will post the event to either the application object, iff the target thread is the main thread, or to an event dispatcher for any other given thread. Since the event dispatcher will exist only after
QThread::run
has been entered, we indicate the requirement for the thread to be running by returning true fromneedsRunningThread
.The metacall posting functions, in their simplest form, require the functor call consumer to provide object for a given thread, and instantiate the functor call event. The implementation of the event is still ahead of us, and is the essential difference between various implementations.
The second overload takes a rvalue reference for the functor, potentially saving a copy operation on the functor. This is helpful if the continuation contains data that is expensive to copy.
For demonstration purposes, the worker thread first posts a metacall to the main thread, and then defers to
QThread::run()
to start an event loop to listen for possible metacalls from other threads. A mutex is used to allow the thread user to wait in a simple fashion for the thread to start, if necessitated by the consumer's implementation. Such wait is necessary for the default event consumer given above.Finally, we start the above worker thread that posts a metacall to the main (application) thread, and the application thread posts a metacall to the worker thread.
The output will look approximately as follows in all implementations. The functors cross the threads: the one created in the main thread is executed in the worker thread, and vice-versa.
Qt 5 Solution Using a Temporary Object as The Signal Source
The simplest approach for Qt 5 is to use a temporary
QObject
as a signal source, and connect the functor to itsdestroyed(QObject*)
signal. WhenpostMetaCall
returns, thesignalSource
gets destructed, emits itsdestroyed
signal, and posts the metacall to the proxy object.This is perhaps the most concise and straightforward implementation in the C++11 style. The
signalSource
object is used in the C++11 RAII fashion for the side effects of its destruction. The phrase "side effects" has a meaning within C++11's semantics and should not be interpreted to mean "unreliable" or "undesirable" - it's anything but.QObject
's contract with us is to emitdestroyed
sometime during the execution of its destructor. We're more than welcome to use that fact.If we only intend to post to the main thread, the code becomes almost trivial:
Qt 4/5 Solution Using QEvent Destructor
The same approach can be applied to
QEvent
directly. The event's virtual destructor can call the functor. The events are deleted right after they are delivered by the consumer object's thread's event dispatcher, so they always execute in the right thread. This will not change in Qt 4/5.To post to main thread only, things become even simpler:
Qt 5 Solution Using the Private QMetaCallEvent
The functor can be wrapped in the Qt 5 slot object payload of the
QMetaCallEvent
. The functor will be invoked byQObject::event
, and thus can be posted to any object in the target thread. This solution uses the private implementation details of Qt 5.Qt 4/5 Solution Using a Custom Event and Consumer
We reimplement the
event()
method of the object, and have it call the functor. This calls for an explicit event consumer object in each thread that the functors are posted to. The object is cleaned up when its thread is finished, or, for the main thread, when the application instance is destructed. It works on both Qt 4 and Qt 5. The use of rvalue references avoids copying of the temporary functor.