简体   繁体   English

动态向一组物体发射信号

[英]Emitting a signal to one object in a set dynamically

I have a situation where I have a single Emitter object and a set of Receivers. 我遇到的情况是我有一个发射器对象和一组接收器。 The receivers are of the same class, and actually represent a set of devices of the same type. 接收器属于同一类别,实际上代表一组相同类型的设备。 I'm using the Qt framework. 我正在使用Qt框架。

  • The Emitter itself first gets a signal asking for information from one of the devices. 发射器本身首先会收到一个信号,要求从其中一个设备获取信息。

  • In the corresponding slot, the Emitter has to check to see which of the Receivers are 'ready', and then send its own signal to request data to one of the devices (whichever is ready first). 在相应的插槽中,发射器必须检查以查看哪些接收器已“就绪”,然后发送其自身的信号以向其中一个设备请求数据(以先准备好者为准)。

The Emitter receives signals very quickly, on the order of milliseconds. 发射器非常快地接收信号,大约为毫秒。 There are three ways I can think of safely requesting data from only one of the devices (the devices live in their own threads, so I need a thread-safe mechanism). 我可以考虑通过三种方式仅从其中一台设备安全地请求数据(这些设备位于各自的线程中,因此我需要一种线程安全的机制)。 The number of devices isn't static, and can change. 设备的数量不是静态的,并且可以更改。 The total number of devices is quite small (definitely under 5-6). 设备总数非常小(肯定在5-6以下)。

1) Connect to all the devices when they are added or removed. 1)添加或删除所有设备时,请连接它们。 Emit the one request and have the devices objects themselves filter out whether the request is for them using some specific device tag. 发出一个请求,并让设备对象自己使用某些特定的设备标签过滤出该请求是否针对他们。 This method is nice because the request slot where the check occurs will execute in a dedicated thread's context, but wasteful as the number of devices go up. 这种方法很好,因为执行检查的请求插槽将在专用线程的上下文中执行,但随着设备数量的增加而浪费。

2) Connect and disconnect from the object within the Emitter on the fly when it's necessary to send a request. 2)需要发送请求时,即时连接发射器内的对象并与之断开连接。

3) Use QMetaObject::invokeMethod() when its necessary to send a request. 3)必要时使用QMetaObject :: invokeMethod()发送请求。

Performance is important. 性能很重要。 Does anyone know which method is the 'best', or if there's a better one altogether? 有谁知道哪种方法是“最好的”,或者是否有更好的方法?

Regards 问候

Pris 普里斯

Note: To clarify: Emitter gets a signal from the application, to get info by querying the device. 注意:需要说明的是:发射器从应用程序获取信号,通过查询设备获取信息。 Crazy ASCII art go: 疯狂的ASCII艺术去:

(app)<---->(emitter)<------>(receivers)<--|-->physical devices (app)<---->(发射器)<------>(接收器)<-|->物理设备

I'm amusing here this is multi thread environment. 我在这里有趣的是多线程环境。

If you are restricted to Qt signal / slot system between then the answer for your specific questions: 如果您被限制在Qt信号/插槽系统之间,则针对特定问题的答案:

1) is definitely not the way to go. 1)绝对不是要走的路。 On an emit from the Emitter a total number of events equal to the number of Receivers will be queued for the thread(s) event loops of the devices, then the same number of slot calls will occur once the thread(s) reach those event. Emitter发出的事件总数等于Receivers数量的事件将排队等待设备的线程事件循环,然后一旦线程到达这些事件,将发生相同数量的插槽调用。 Even if most of the lost just if(id!=m_id) return; 即使大多数丢失的只是if(id!=m_id) return; on their first line, its a significant amount of things going on in the core of Qt. 在他们的第一行中,它在Qt的核心中发生了大量事情。 Place a breakpoint in one of your slots that is evoked by a Qt::QueuedConnection signal and validate this looking at the actual stack trace. 将一个断点放在Qt::QueuedConnection信号引起的插槽中,并在实际的堆栈跟踪中进行验证。 Its usually at least 4 call deep from the xyEventLoop::processEvents(...) , so "just returning" is definitely not "free" in terms of time. 通常,它至少要从xyEventLoop::processEvents(...)进行至少4次调用,因此就时间而言,“仅返回”绝对不是“免费的”。

2) Not sure how Qt's inner implementation actually is, but from what I know connecting and disconnecting most likely include inserting and removing the sender and receiver into some lists, which are most likely accessed with QMutex locking. 2)不确定Qt的内部实现实际上如何,但是据我所知,连接和断开连接最有可能包括将发送方和接收方插入和删除到某些列表中,这些列表很可能通过QMutex锁定进行访问。 - might also be "expensive" time-wise, and rapidly connecting and disconnecting is definitely not a best practice. -有时也可能是“昂贵的”,快速连接和断开连接绝对不是最佳实践。

3) Probably the least "expensive time-wise" solution you can find that is still using Qt's singnal-slot system. 3)可能是您发现仍在使用Qt的单槽系统的最“昂贵的按时”解决方案。

optionally) Take a look at QSignalMapper . (可选)看看QSignalMapper It is designed exactly for what you planned to do in option 1). 它完全按照您计划在选项1)中执行的操作而设计。

There are more optimal solutions to communicate between your Emitter and Receivers , but as a best practice I'd first choose the option that is most easy to use and fast to implement, yet has a chance of being fast enough run-time (that is option 3). 在您的Emitter ReceiversReceivers之间有更多的最佳通信解决方案,但是作为最佳实践,我首先选择最易于使用和快速实施的选项,但有可能会足够快的运行时间(即选项3)。 ). )。 Then, when its done, see if it meets your performance requirements. 然后,完成后,查看它是否满足您的性能要求。 If it does not, and only then, consider using shared memory with mutexes in a data provider - data consumer architecture ( Emitter thread rapidly post request data in a circular list, while the Receiver thread(s) reads them whenever have time, then post results back a similar way, while the Emitter thread constantly polls for done results.) 如果不是,只有这样,才考虑在数据提供者-数据使用者体系结构中将共享内存与互斥锁一起使用( Emitter线程将请求数据快速发布到循环列表中,而Receiver线程在有时间的时候读取它们,然后发布结果以类似的方式返回,而Emitter线程不断轮询完成的结果。)

Based on the information you have provided I would still recommend a Reactor implementation. 根据您提供的信息,我仍然建议使用Reactor实施。 If you don't use ACE then you can implement your own. 如果您不使用ACE,则可以实现自己的。 The basic architecture is as follows: 基本架构如下:

  1. use select to wake up when signal or data is received from the App. 从应用程序接收到信号或数据时,请使用select唤醒。
  2. If there is a socket ready on the sending list then you just pick one and send it data 如果发送列表上已准备好套接字,则只需选择一个套接字并发送数据即可
  3. When data is sent the Receiver removes itself from the set of sockets/handlers that are available 发送数据后, Receiver会将自己从可用的套接字/处理程序集中删除
  4. When data is processed the Reciever re-registers itself to the list of available recipients. 处理数据后,接收方Reciever自己重新注册到可用收件人列表中。

The reason I suggested ACE is because it has one of the simplest to use implementations of the Reactor pattern. 我之所以建议ACE是因为它具有Reactor模式的最简单使用的实现之一。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM