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

Bagaimana untuk Melaksanakan Fungsi atau Lambdas dalam Benang Khusus dalam Qt?

Mary-Kate Olsen
Mary-Kate Olsenasal
2024-12-21 10:45:08670semak imbas

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

Melaksanakan Fungsi atau Lambdas dalam Benang Diberi dalam Qt, Gaya GCD

Masalah:

Dalam Objektif-C dengan GCD, seseorang boleh melaksanakan lambda atau fungsi dalam mana-mana benang yang memutar gelung peristiwa. Contohnya, menghantar sesuatu ke baris gilir utas utama boleh dilakukan secara serentak atau tidak segerak:

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

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

Bagaimana ini boleh dicapai dalam Qt?

Penyelesaian:

Qt 5.10 & Up

Untuk Qt 5.10 dan lebih baru, penyelesaian paling mudah ialah menggunakan QMetaObject::invokeMethod:

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

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

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

Untuk functors:

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

Untuk Qt 5/4, terdapat beberapa kaedah:

  • Menyiarkan melalui QEvent: Cipta acara tersuai FunctorCallEvent dan laksanakan objek pengguna FunctorCallConsumer.
  • Penyiaran melalui Objek Sementara: Gunakan QObject sementara sebagai sumber isyarat dan sambungkan functor kepada yang dimusnahkan() isyarat.
  • Menyiarkan melalui QMetaCallEvent (Qt 5 Private): Balut functor dalam QtPrivate peribadi::QFunctorSlotObject dan gunakan QMetaCallEvent.
  • Menyiarkan melalui Object Pengguna Acara: Gantikan kaedah acara() objek untuk dipanggil functor.

Kod Biasa:

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

Demonstrasi:

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

Output:

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")

Atas ialah kandungan terperinci Bagaimana untuk Melaksanakan Fungsi atau Lambdas dalam Benang Khusus dalam Qt?. 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