Heim > Backend-Entwicklung > C++ > Wie führe ich Funktoren oder Lambdas in einem bestimmten Thread in Qt aus?

Wie führe ich Funktoren oder Lambdas in einem bestimmten Thread in Qt aus?

Mary-Kate Olsen
Freigeben: 2024-12-21 10:45:08
Original
630 Leute haben es durchsucht

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

Ausführen von Funktoren oder Lambdas in einem gegebenen Thread in Qt, GCD-Stil

Problem:

In Objective-C Mit GCD kann man ein Lambda oder eine Funktion in jedem Thread ausführen, der eine Ereignisschleife dreht. Beispielsweise kann das Senden von etwas an die Warteschlange des Hauptthreads synchron oder asynchron erfolgen:

dispatch_sync(dispatch_get_main_queue(), ^{ /* do sth */ });

dispatch_async(dispatch_get_main_queue(), ^{ /* do sth */ });
Nach dem Login kopieren

Wie kann dies in Qt erreicht werden?

Lösung:

Qt 5,10 und höher

Für Qt 5.10 und höher ist die einfachste Lösung die Verwendung von QMetaObject::invokeMethod:

QMetaObject::invokeMethod(qApp, []{ ... });

QMetaObject::invokeMethod(obj, []{ ... });

QMetaObject::invokeMethod(QAbstractEventDispatcher::instance(thread),
                         []{ ... });
Nach dem Login kopieren

Für Funktoren:

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));
}
Nach dem Login kopieren

Qt 5/4

Für Qt 5/4 gibt es mehrere Methoden:

  • Posten über QEvent: Erstellen Sie ein benutzerdefiniertes Ereignis FunctorCallEvent und implementieren Sie ein Verbraucherobjekt FunctorCallConsumer.
  • Posten über temporäres Objekt: Verwenden Sie ein temporäres QObject als Signalquelle und verbinden Sie den Funktor mit seinem destroy() Signal.
  • Posten über QMetaCallEvent (Qt 5 Private):Verpacken Sie den Funktor in das private QtPrivate::QFunctorSlotObject und verwenden Sie ein QMetaCallEvent.
  • Posten über Objekt Ereigniskonsument: Überschreiben Sie die event()-Methode eines Objekts, um das aufzurufen Funktor.

Common Code:

#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));
}
Nach dem Login kopieren

Demonstration:

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();
}
Nach dem Login kopieren

Ausgabe:

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")
Nach dem Login kopieren

Das obige ist der detaillierte Inhalt vonWie führe ich Funktoren oder Lambdas in einem bestimmten Thread in Qt aus?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Neueste Artikel des Autors
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage