如何监控 Qt 信号事件队列深度 [英] How to Monitor Qt Signal Event Queue Depth

查看:369
本文介绍了如何监控 Qt 信号事件队列深度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的程序中有两个对象.一个物体正在发射信号.另一个在一个时隙中接收信号并一个一个地处理传入的信号.两个对象都在不同的线程中运行.现在我需要测量和监控接收对象的工作量.

There are two objects in my program. One object is emitting a signal. The other one receives the signal in a slot and processes the incoming signals one by one. Both objects are running in different threads. Now I need to measure and monitor the workload for my receiving object.

问题是我不知道 Qt 信号队列中有多少信号在等待我的第二个对象处理.有没有办法获得这个队列的大小?或者有没有办法知道有多少信号需要处理?

The problem is I do not know how many signals are waiting for my second object to process in the Qt signal queue. Is there a way to get the size of this queue? Or is there a work around to know how many signals have to be still proecessed?

推荐答案

qGlobalPostedEventsCount() 是一个起点,尽管它只适用于当前线程.

The qGlobalPostedEventsCount() is a starting point, although it only works for the current thread.

要轮询任意线程,我们可以使用 Qt 的内部结构.那么实现就非常简单了.即使线程被阻塞并且不处理事件,它也能工作.

To poll an arbitrary thread, we can to use Qt's internals. The implementation is then very simple. It works even when the thread is blocked and doesn't process events.

// https://github.com/KubaO/stackoverflown/tree/master/questions/queue-poll-44440584
#include <QtCore>
#include <private/qthread_p.h>
#include <climits>

uint postedEventsCountForThread(QThread * thread) {
   if (!thread)
      return -1;
   auto threadData = QThreadData::get2(thread);
   QMutexLocker lock(&threadData->postEventList.mutex);
   return threadData->postEventList.size() - threadData->postEventList.startOffset;
}

uint postedEventsCountFor(QObject * target) {
   return postedEventsCountForThread(target->thread());
}

如果真的不希望使用私有 API,我们可以有一个不那么直接的解决方案,但需要更多的开销.首先,让我们回想一下,在某个对象的线程中做事"的最低开销方式是在事件的析构函数中做所说的事"——见 此答案了解更多详情.我们可以将最高优先级的事件发布到目标对象的事件队列.该事件包装了一个调用 qGlobalPostedEventsCount 的任务,更新计数变量,并释放我们随后获取的互斥锁.在获取互斥锁时,计数具有返回的有效值.如果目标线程无响应且请求超时,则返回 -1.

If one really wishes not to use private APIs, we can have a less straightforward solution with more overhead. First, let's recall that the lowest overhead means of "doing stuff in some object's thread" is to do said "stuff" in an event's destructor - see this answer for more details. We can post the highest priority event to the target object's event queue. The event wraps a task that invokes qGlobalPostedEventsCount, updates the count variable, and releases a mutex that we then acquire. At the time of mutex acquisition, the count has a valid value that is returned. If the target thread is unresponsive and the request times out, -1 is returned.

uint qGlobalPostedEventsCount(); // exported in Qt but not declared
uint postedEventsCountForPublic(QObject * target, int timeout = 1000) {
   uint count = -1;
   QMutex mutex;
   struct Event : QEvent {
      QMutex & mutex;
      QMutexLocker lock;
      uint & count;
      Event(QMutex & mutex, uint & count) :
         QEvent(QEvent::None), mutex(mutex), lock(&mutex), count(count) {}
      ~Event() {
         count = qGlobalPostedEventsCount();
      }
   };
   QCoreApplication::postEvent(target, new Event(mutex, count), INT_MAX);
   if (mutex.tryLock(timeout)) {
      mutex.unlock();
      return count;
   }
   return -1;
}

还有一个测试工具:

int main(int argc, char ** argv) {
   QCoreApplication app(argc, argv);
   struct Receiver : QObject {
      bool event(QEvent *event) override {
         if (event->type() == QEvent::User)
            QThread::currentThread()->quit();
         return QObject::event(event);
      }
   } obj;
   struct Thread : QThread {
      QMutex mutex;
      Thread() { mutex.lock(); }
      void run() override {
         QMutexLocker lock(&mutex);
         QThread::run();
      }
   } thread;
   thread.start();
   obj.moveToThread(&thread);
   QCoreApplication::postEvent(&obj, new QEvent(QEvent::None));
   QCoreApplication::postEvent(&obj, new QEvent(QEvent::None));
   QCoreApplication::postEvent(&obj, new QEvent(QEvent::None));
   QCoreApplication::postEvent(&obj, new QEvent(QEvent::User));
   auto count1 = postedEventsCountFor(&obj);
   thread.mutex.unlock();
   auto count2 = postedEventsCountForPublic(&obj);
   thread.wait();
   auto count3 = postedEventsCountFor(&obj);
   Q_ASSERT(count1 == 4);
   Q_ASSERT(count2 == 4);
   Q_ASSERT(count3 == 0);
}

QT = core-private
CONFIG += console c++11
CONFIG -= app_bundle
TARGET = queue-poll-44440584
TEMPLATE = app
SOURCES += main.cpp

这篇关于如何监控 Qt 信号事件队列深度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆