首頁 >後端開發 >C++ >如何在 Qt 的特定執行緒中執行函子或 Lambda?

如何在 Qt 的特定執行緒中執行函子或 Lambda?

Mary-Kate Olsen
Mary-Kate Olsen原創
2024-12-21 10:45:08634瀏覽

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

在Qt 的給定線程中執行Functor 或Lambda,GCD 風格

問題:

問題:

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

dispatch_async(dispatch_get_main_queue(), ^{ /* do sth */ });
在中使用GCD,可以在任何旋轉事件循環的線程中執行lambda 或函數。例如,向主執行緒佇列調度某些內容可以同步或非同步完成:

這在 Qt 中如何實現?

解決方案:

Qt 5.10 & Up

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

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

QMetaObject::invokeMethod(QAbstractEventDispatcher::instance(thread),
                         []{ ... });
對於Qt 5.10 及更高版本,最簡單的解決方案是使用QMetaObject::invokeMethod:

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));
}
對函子:

Qt 5/4

    對於Qt 5/4,有Qt以下幾種方法:
  • 透過QEvent 發佈:
  • 建立自訂事件 FunctorCallEvent 並實作消費者物件 FunctorCallConsumer。
  • 透過臨時物件發布:
  • 使用臨時 QObject 作為訊號來源並將函子連接到其destroy() 訊號。
  • 透過 QMetaCallEvent (Qt 5 Private) 發佈:
  • 將函子包裝在私有 QtPrivate::QFunctorSlotObject 中並使用 QMetaCallEvent。
  • 透過物件事件消費者發布:
覆蓋物件的 event()方法來調用

通用代碼:
#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));
}

演示:
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();
}

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")
輸出:

以上是如何在 Qt 的特定執行緒中執行函子或 Lambda?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn