Rumah >pembangunan bahagian belakang >C++ >Bagaimana untuk Melaksanakan Fungsi atau Lambdas dalam Benang Qt Tertentu?

Bagaimana untuk Melaksanakan Fungsi atau Lambdas dalam Benang Qt Tertentu?

Susan Sarandon
Susan Sarandonasal
2024-12-16 21:08:11877semak imbas

How to Execute Functors or Lambdas in Specific Qt Threads?

Bagaimana untuk melaksanakan functor atau lambda dalam urutan tertentu dalam Qt, gaya GCD?

Masalah:

Dalam ObjC dengan GCD, anda boleh melaksanakan lambda dalam mana-mana benang yang memutar gelung peristiwa menggunakan fungsi dispatch_sync atau dispatch_async. Ia melaksanakan sesuatu (bersamaan dengan [] { /* do sth */ } dalam C ) dalam baris gilir benang utama, sama ada menyekat atau tidak segerak. Bagaimanakah anda boleh melakukan perkara yang sama dalam Qt?

Penyelesaian:

Dalam Qt, anda boleh mencapai gelagat yang serupa dengan menyampaikan peristiwa yang membungkus functor kepada objek pengguna berada dalam urutan yang dikehendaki, satu proses yang dikenali sebagai penyiaran metacall. Begini cara anda boleh melakukannya:

Qt 5.10 ke atas TL;DR

// invoke on the main thread
QMetaObject::invokeMethod(qApp, []{ ... });

// invoke on an object's thread
QMetaObject::invokeMethod(obj, []{ ... });

// invoke on a particular thread
QMetaObject::invokeMethod(QAbstractEventDispatcher::instance(thread),
                         []{ ... });

TL;DR untuk functors Qt 5.10 ke atas

// https://github.com/KubaO/stackoverflown/tree/master/questions/metacall-21646467

// Qt 5.10 & up - it's all done

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));
}

TL;DR untuk kaedah/slot Qt 5.10 ke atas

// Qt 5/4
template <typename T, typename R>
static void postToObject(T * obj, R(T::* method)()) {
   struct Event : public QEvent {
      T * obj;
      R(T::* method)();
      Event(T * obj, R(T::*method)()):
         QEvent(QEvent::None), obj(obj), method(method) {}
      ~Event() { (obj->*method)(); }
   };
   if (qobject_cast<QThread*>(obj))
      qWarning() << "posting a call to a thread object - this may be a bug";
   QCoreApplication::postEvent(obj, new Event(obj, method));
}

Qt 5.10 ke atas TL;DR: Bagaimana pula dengan pemasa pukulan tunggal?

template <typename F>
static void postToObject(F &amp;&amp; fun, QObject * obj = qApp) {
   if (qobject_cast<QThread*>(obj))
      qWarning() << "posting a call to a thread object - consider using postToThread";
   QTimer::singleShot(0, obj, std::forward<F>(fun));
}

Kod Biasa Qt 5.10 & up

#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

Penyelesaian Qt 4/5 Menggunakan Objek Sementara Sebagai Sumber Isyarat

#include <QtCore>
#include <functional>

namespace FunctorCallConsumer { QObject * forThread(QThread*); }

#define HAS_POSTMETACALL
void postMetaCall(QThread * thread, const std::function<void()> &amp; fun) {
   QObject signalSource;
   QObject::connect(&amp;signalSource, &amp;QObject::destroyed,
                    FunctorCallConsumer::forThread(thread), [=](QObject*){ fun(); });
}
#ifdef __cpp_init_captures
void postMetaCall(QThread * thread, std::function<void()> &amp;&amp; fun) {
   QObject signalSource;
   QObject::connect(&amp;signalSource, &amp;QObject::destroyed,
                    FunctorCallConsumer::forThread(thread), [fun(std::move(fun))](QObject*){ fun(); });
}
#endif

Menggunakan Penyelesaian Qt 4/5 QEvent Destructor

#include <QtCore>
#include <functional>

class FunctorCallEvent : public QEvent {
   std::function<void()> m_fun;
   QThread * m_thread;
public:
   FunctorCallEvent(const std::function<void()> &amp; fun, QObject * receiver) :
      QEvent(QEvent::None), m_fun(fun), m_thread(receiver->thread()) {}
   FunctorCallEvent(std::function<void()> &amp;&amp; fun, QObject * receiver) :
      QEvent(QEvent::None), m_fun(std::move(fun)), m_thread(receiver->thread()) { qDebug() << "move semantics"; }
   ~FunctorCallEvent() {
      if (QThread::currentThread() == m_thread)
         m_fun();
      else
         qWarning() << "Dropping a functor call destined for thread" << m_thread;
   }
};

Penyelesaian Qt 5 Menggunakan QMetaCallEvent Persendirian

#include <QtCore>
#include <private/qobject_p.h>
#include <functional>

class FunctorCallEvent : public QMetaCallEvent {
public:
   template <typename Functor>
   FunctorCallEvent(Functor &amp;&amp; fun, QObject * receiver) :
      QMetaCallEvent(new QtPrivate::QFunctorSlotObject<Functor, 0, typename QtPrivate::List_Left<void, 0>::Value, void>
                     (std::forward<Functor>(fun)), receiver, 0, 0, 0, (void**)malloc(sizeof(void*))) {}
};

Penyelesaian Qt 4/5 Menggunakan Acara Tersuai dan Pengguna

#include <QtCore>
#include <functional>

class FunctorCallEvent : public QEvent {
   std::function<void()> m_fun;
public:
   FunctorCallEvent(const std::function<void()> &amp; fun, QObject *) :
      QEvent(QEvent::None), m_fun(fun) {}
   FunctorCallEvent(std::function<void()> &amp;&amp; fun, QObject *) :
      QEvent(QEvent::None), m_fun(std::move(fun)) { qDebug() << "move semantics"; }
   void call() { m_fun(); }
};

#define HAS_FUNCTORCALLCONSUMER
class FunctorCallConsumer : public QObject {
   typedef QMap<QThread*, FunctorCallConsumer*> Map;
   static QObject * m_appThreadObject;
   static QMutex m_threadObjectMutex;
   static Map m_threadObjects;
   bool event(QEvent * ev) {
      if (!dynamic_cast<FunctorCallEvent*>(ev)) return QObject::event(ev);
      static_cast<FunctorCallEvent*>(ev)->call();
      return true;
   }
};

Atas ialah kandungan terperinci Bagaimana untuk Melaksanakan Fungsi atau Lambdas dalam Benang Qt Tertentu?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn