>백엔드 개발 >C++ >Qt의 특정 스레드에서 Functor 또는 Lambda를 실행하는 방법은 무엇입니까?

Qt의 특정 스레드에서 Functor 또는 Lambda를 실행하는 방법은 무엇입니까?

Mary-Kate Olsen
Mary-Kate Olsen원래의
2024-12-21 10:45:08631검색

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

Qt, GCD 스타일의 지정된 스레드에서 Functor 또는 Lambda 실행

문제:

Objective-C에서 GCD를 사용하면 이벤트 루프를 회전시키는 모든 스레드에서 람다 또는 함수를 실행할 수 있습니다. 예를 들어, 메인 스레드의 큐에 무언가를 디스패치하는 것은 동기식 또는 비동기식으로 수행될 수 있습니다.

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

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

Qt에서 이를 어떻게 달성할 수 있습니까?

해결책:

Qt 5.10 & Up

Qt 5.10 이상의 경우 가장 간단한 해결책은 QMetaObject::invokeMethod:

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

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

QMetaObject::invokeMethod(QAbstractEventDispatcher::instance(thread),
                         []{ ... });

펑터의 경우:

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에는 여러 가지 방법이 있습니다.

  • QEvent를 통해 게시: 사용자 정의 이벤트 FunctorCallEvent를 만들고 구현합니다. 소비자 개체 FunctorCallConsumer.
  • 임시를 통해 게시 Object: 임시 QObject를 신호 소스로 사용하고 functor를 destroy() 신호에 연결합니다.
  • QMetaCallEvent(Qt 5 Private)를 통해 게시: 개인 QtPrivate::QFunctorSlotObject를 사용하고 QMetaCallEvent.
  • 객체 이벤트 소비자를 통해 게시: 객체의 event() 메서드를 재정의하여 functor를 호출합니다.

공통 코드:

#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의 특정 스레드에서 Functor 또는 Lambda를 실행하는 방법은 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.