动态地向集合中的一个对象发出信号

Emitting a signal to one object in a set dynamically

本文关键字:一个对象 信号 集合 动态      更新时间:2023-10-16

我有一种情况,我有一个Emitter对象和一组Receiver。接收器属于同一类,并且实际上代表一组相同类型的设备。我使用的是Qt框架。

  • 发射器本身首先从其中一个设备获得请求信息的信号。

  • 在相应的插槽中,发射器必须检查哪些接收器"准备就绪",然后发送自己的信号,向其中一个设备(先准备就绪的设备)请求数据。

发射器接收信号的速度非常快,以毫秒为单位。我有三种方法可以安全地从其中一个设备请求数据(这些设备位于它们自己的线程中,所以我需要一个线程安全机制)。设备的数量不是静态的,并且可以更改。设备的总数相当少(肯定在5-6台以下)。

1) 添加或删除所有设备时,请连接到这些设备。发出一个请求,并让设备对象自己使用某个特定的设备标记来过滤该请求是否针对它们。这种方法很好,因为发生检查的请求槽将在专用线程的上下文中执行,但随着设备数量的增加而浪费。

2) 当需要发送请求时,在飞行中连接和断开发射器内的对象。

3) 当需要发送请求时,请使用QMetaObject::invokeMethod()。

性能很重要。有人知道哪种方法是"最好的"吗?或者是否有更好的方法?

问候

Pris

注意:为了澄清:发射器从应用程序中获得信号,通过查询设备来获取信息。疯狂的ASCII艺术围棋:

(应用程序)<---->(发射器)<----->(接收器)<-|-->物理设备

根据您提供的信息,我仍然建议使用Reactor实现。如果您不使用ACE,那么您可以实现自己的ACE。基本架构如下:

  1. 当从应用程序接收到信号或数据时,使用select唤醒
  2. 如果发送列表上有一个套接字,那么您只需选择一个套接字并将数据发送给它
  3. 发送数据时,Receiver会将自身从可用的套接字/处理程序集中删除
  4. 处理数据时,Reciever会将自身重新注册到可用收件人列表中

我之所以建议使用ACE,是因为它是Reactor模式中使用最简单的实现之一。

我很有趣,这是一个多线程环境。

如果您被限制在Qt信号/插槽系统之间,那么您的特定问题的答案是:

1) 绝对不是该走的路。在从Emitter发出时,将为设备的线程事件循环排队的事件总数等于Receivers的数量,然后一旦线程到达这些事件,将发生相同数量的槽调用。即使大多数人在第一行只输了if(id!=m_id) return;,Qt的核心仍有大量的事情在发生。在Qt::QueuedConnection信号引起的一个插槽中放置一个断点,并通过实际堆栈跟踪进行验证。它通常至少有4个来自xyEventLoop::processEvents(...)的调用,所以"只是返回"在时间上肯定不是"免费的"。

2) 不确定Qt的内部实现实际上是什么,但据我所知,连接和断开连接很可能包括将发送方和接收方插入和删除到一些列表中,这些列表很可能通过QMutex锁定访问。-从时间角度来看,这可能也是"昂贵的",快速连接和断开连接绝对不是最佳做法。

3) 也许你能找到的"时间上最便宜"的解决方案仍然使用Qt的单槽系统。

可选)查看QSignalMapper。它正是为您在选项1)中计划做的事情而设计的。

EmitterReceivers之间有更优化的通信解决方案,但作为最佳实践,我会首先选择最易于使用和快速实现的选项,但有可能在运行时足够快(即选项3)。然后,完成后,看看它是否符合您的性能要求。如果没有,并且只有在那时,才考虑在数据提供者-数据使用者体系结构中使用具有互斥的共享内存(Emitter线程在循环列表中快速发布请求数据,而Receiver线程只要有时间就会读取这些数据,然后以类似的方式发布结果,同时Emitter线程不断轮询已完成的结果。)

相关文章: