Maison > développement back-end > C++ > Comment exécuter des foncteurs ou des Lambdas dans un thread spécifique dans Qt ?

Comment exécuter des foncteurs ou des Lambdas dans un thread spécifique dans Qt ?

Mary-Kate Olsen
Libérer: 2024-12-21 10:45:08
original
630 Les gens l'ont consulté

How to Execute Functors or Lambdas in a Specific Thread in Qt?

Exécution de foncteurs ou de Lambdas dans un thread donné dans Qt, style GCD

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 */ });
Copier après la connexion

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),
                         []{ ... });
Copier après la connexion

Pour les foncteurs :

template <typename F>
static void postToObject(F &amp;&amp;fun, QObject *obj = qApp) {
  QMetaObject::invokeMethod(obj, std::forward<F>(fun));
}

template <typename F>
static void postToThread(F &amp;&amp; fun, QThread *thread = qApp->thread()) {
   auto *obj = QAbstractEventDispatcher::instance(thread);
   Q_ASSERT(obj);
   QMetaObject::invokeMethod(obj, std::forward<F>(fun));
}
Copier après la connexion

Qt 5/4

Pour Qt 5/4, il en existe plusieurs méthodes :

  • Publication via QEvent : Créez un événement personnalisé FunctorCallEvent et implémentez un objet consommateur FunctorCallConsumer.
  • Publication via un objet temporaire : Utilisez un QObject temporaire comme source de signal et connectez le foncteur à son destroy() signal.
  • Publication via QMetaCallEvent (Qt 5 Private) : Enveloppez le foncteur dans le QtPrivate::QFunctorSlotObject privé et utilisez un QMetaCallEvent.
  • Publication via Object Consommateur d'événements : Remplacez la méthode event() d'un objet pour appeler le foncteur.

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()> &amp; fun) {
   auto receiver = FunctorCallConsumer::forThread(thread);
   QCoreApplication::postEvent(receiver, new FunctorCallEvent(fun, receiver));
}

void postMetaCall(QThread * thread, std::function<void()> &amp;&amp; fun) {
   auto receiver = FunctorCallConsumer::forThread(thread);
   QCoreApplication::postEvent(receiver,
                               new FunctorCallEvent(std::move(fun), receiver));
}
Copier après la connexion

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:" << &amp;worker;
   qDebug() << "main thread:" << QThread::currentThread();
   if (FunctorCallConsumer::needsRunningThread()) {
      worker.start();
      worker.waitForStart();
   }
   postMetaCall(&amp;worker, []{ qDebug() << "main functor executes in thread" << QThread::currentThread(); });
   if (!FunctorCallConsumer::needsRunningThread()) worker.start();
   QMetaObject::invokeMethod(&amp;a, "quit", Qt::QueuedConnection);
   return a.exec();
}
Copier après la connexion

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")
Copier après la connexion

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!

source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal