Problem:
In Qt, you want to execute a lambda or a functor in any thread that has an event loop, similar to GCD's dispatch queues in Objective-C.
Solution:
The solution centers around delivering an event that wraps the functor to a consumer object residing in the desired thread. This operation is referred to as metacall posting, and it can be implemented in several ways.
Qt 5.10 & Up TL;DR:
You can invoke methods on QObjects or QThreads directly:
// Invoke on the main thread QMetaObject::invokeMethod(qApp, []{ ... }); // Invoke on an object's thread QMetaObject::invokeMethod(obj, []{ ... }); // Invoke on a particular thread QMetaObject::invokeMethod( QAbstractEventDispatcher::instance(thread), []{ ... });
TL;DR for Functors:
Several template functions are provided to wrap the functor in an appropriate event object, making metacall posting convenient.
// Post to the main thread sync void execInMainThread_sync(std::function<void(void)> func) { if(qApp->thread() == QThread::currentThread()) func(); else { ((App*) qApp)->invokeGenericExec(func, Qt::BlockingQueuedConnection); } } // Post to the main thread async void execInMainThread_async(std::function<void(void)> func) { ((App*) qApp)->invokeGenericExec(func, Qt::QueuedConnection); }
TL;DR for Methods/Slots:
For methods or slots, a macro is defined to handle the metacall posting.
#define POST_METHOD(obj, method) \ QObject src; \ QObject::connect(&src, &QObject::destroyed, obj, method, \ Qt::QueuedConnection);
Common Code:
The provided code includes common helper functions and macros that abstract the metacall posting implementation for use in different scenarios.
Example:
void test1() { QThread t; QObject o; o.moveToThread(&t); // Execute in given object's thread postToObject([&]{ o.setObjectName("hello"); }, &o); // or postToObject(std::bind(&QObject::setObjectName, &o, "hello"), &o); // Execute in given thread postToThread([]{ qDebug() << "hello from worker thread"; }); // Execute in the main thread postToThread([]{ qDebug() << "hello from main thread"; }); }
Additional Note:
If your target thread does not have an event loop, such as a worker thread, you may need a mechanism to start the event loop within the thread. For example, if using a single-shot timer for metacall posting, you can start the event loop using QThread::exec().
The above is the detailed content of How to Execute Functors or Lambdas in a Specific Qt Thread, Similar to GCD?. For more information, please follow other related articles on the PHP Chinese website!