Problème :
En Objective-C avec GCD, on peut exécuter un lambda ou une fonction dans n'importe quel thread qui fait tourner une boucle d'événement. Par exemple, la distribution de quelque chose dans la file d'attente du thread principal peut être effectuée de manière synchrone ou asynchrone :
dispatch_sync(dispatch_get_main_queue(), ^{ /* do sth */ }); dispatch_async(dispatch_get_main_queue(), ^{ /* do sth */ });
Comment cela peut-il être réalisé dans Qt ?
Solution :
Qt 5.10 et versions ultérieures
Pour Qt 5.10 et versions ultérieures, la solution la plus simple est d'utiliser QMetaObject::invokeMethod:
QMetaObject::invokeMethod(qApp, []{ ... }); QMetaObject::invokeMethod(obj, []{ ... }); QMetaObject::invokeMethod(QAbstractEventDispatcher::instance(thread), []{ ... });
Pour les foncteurs :
template <typename F> static void postToObject(F &&fun, QObject *obj = qApp) { QMetaObject::invokeMethod(obj, std::forward<F>(fun)); } template <typename F> static void postToThread(F && fun, QThread *thread = qApp->thread()) { auto *obj = QAbstractEventDispatcher::instance(thread); Q_ASSERT(obj); QMetaObject::invokeMethod(obj, std::forward<F>(fun)); }
Qt 5/4
Pour Qt 5/4, il en existe plusieurs méthodes :
Code commun :
#ifndef HAS_FUNCTORCALLCONSUMER namespace FunctorCallConsumer { bool needsRunningThread() { return true; } QObject * forThread(QThread * thread) { Q_ASSERT(thread); QObject * target = thread == qApp->thread() ? static_cast<QObject*>(qApp) : QAbstractEventDispatcher::instance(thread); Q_ASSERT_X(target, "postMetaCall", "the receiver thread must have an event loop"); return target; } } #endif void postMetaCall(QThread * thread, const std::function<void()> & fun) { auto receiver = FunctorCallConsumer::forThread(thread); QCoreApplication::postEvent(receiver, new FunctorCallEvent(fun, receiver)); } void postMetaCall(QThread * thread, std::function<void()> && fun) { auto receiver = FunctorCallConsumer::forThread(thread); QCoreApplication::postEvent(receiver, new FunctorCallEvent(std::move(fun), receiver)); }
Démonstration :
class Worker : public QThread { QMutex m_started; void run() { m_started.unlock(); postMetaCall(qApp->thread(), []{ qDebug() << "worker functor executes in thread" << QThread::currentThread(); }); QThread::run(); } public: Worker(QObject * parent = 0) : QThread(parent) { m_started.lock(); } ~Worker() { quit(); wait(); } void waitForStart() { m_started.lock(); m_started.unlock(); } }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); a.thread()->setObjectName("main"); Worker worker; worker.setObjectName("worker"); qDebug() << "worker thread:" << &worker; qDebug() << "main thread:" << QThread::currentThread(); if (FunctorCallConsumer::needsRunningThread()) { worker.start(); worker.waitForStart(); } postMetaCall(&worker, []{ qDebug() << "main functor executes in thread" << QThread::currentThread(); }); if (!FunctorCallConsumer::needsRunningThread()) worker.start(); QMetaObject::invokeMethod(&a, "quit", Qt::QueuedConnection); return a.exec(); }
Sortie :
worker thread: QThread(0x7fff5692fc20, name = "worker") main thread: QThread(0x7f86abc02f00, name = "main") main functor executes in thread QThread(0x7fff5692fc20, name = "worker") worker functor executes in thread QThread(0x7f86abc02f00, name = "main")
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!