赞
踩
Listener是除WaitSet之外实现推送方法来检测特定事件并对其作出反应。监听器为用户提供了附加具有相应事件和回调的对象的能力。每当对象接收到指定的事件时,就会在Listener后台线程中调用相应的回调作为响应。
WaitSet的两个关键区别是侦听器是事件驱动的而不是像WaitSet和Listener创建的那样由事件和状态驱动一个单独的后台线程,在该线程中执行事件回调,而在WaitSet中用户必须显式调用事件回调。
##术语
-条件变量
由附加对象用于通知Listener/WaitSet事件发生。
-事件正在更改对象的状态。
-事件驱动由事件直接引起的一次性反应。
示例:一个新样本已发送给一个订阅者。
-状态对象成员设置为的预定义值。
-状态驱动重复反应,该反应持续到状态持续存在。
示例:订阅者存储了未经用户检查的样本。
监听器是 反应器模式 的变体用法应该类似于_WaitSet_,但有一个关键区别——它应该是事件驱动的,而不是事件和状态驱动的混合,这取决于附加的事件,就像在_WaitSet中一样。
detachEvent
是非阻塞的。事件在“detachEvent”调用之后立即分离。+---------------------------+ | ConditionVariableData | | - m_semaphore | | - m_runtimeName | | - m_toBeDestroyed | | - m_activeNotifications | +---------------------------+ | 1 | 1 | | | 1 | n +-----------------------------------------------+ +--------------------------------------------------+ | ConditionListener | | ConditionNotifier | | ConditionListener(ConditionVariableData & ) | | ConditionNotifier(ConditionVariableData &, | | | | uint64_t notificationIndex) | | bool wasNotified() | | | | void destroy() | | void notify() | | NotificationVector_t wait() | | | | NotificationVector_t timedWait() | | - m_condVarDataPtr : ConditionVariableData* | | | | - m_notificationIndex | | - m_condVarDataPtr : ConditionVariableData* | +--------------------------------------------------+ | - m_toBeDestroyed : std::atomic_bool | | 1 +-----------------------------------------------+ | | 1 | n | +--------------------------------+ | 1 | TriggerHandle | +-------------------------------------------------+ | bool isValid() | | Listener | | bool wasTriggered() | | attachEvent(Triggerable, EventType, Callback) | | void trigger() | | detachEvent(Triggerable, EventType) | | void reset() | | | | void invalidate() | | - m_events : Event_t[] | | void getUniqueId() | | - m_thread : std::thread | | | | - m_conditionListener : ConditionListener | | - m_conditionVariableDataPtr | | | | - m_resetCallback | | +----------------------------+ | | - m_uniqueTriggerId | | | Event_t | | +--------------------------------+ | | void executeCallback() | | | 1 | | bool reset() | | | | | bool init(...) | | | n | | | | +-------------------------------------------------------+ | | - m_origin | | | Triggerable (e.g. Subscriber) | | | - m_callback | | | | | | - m_invalidationCallback | | | void invalidateTrigger(const uint64_t triggerId) | | | - m_eventId | | | void enableEvent(TriggerHandle&&, const EventEnum ) | | +----------------------------+ | | void enableEvent(TriggerHandle&&) | +-------------------------------------------------+ | void disableEvent(const EventEnum) | | void disableEvent() | | | | - m_triggerHandle : TriggerHandle | +-------------------------------------------------------+
Triggerable不需要实现所有的“enableEvent”,disableEvent
变体,仅限使用所需的变体案例“enableEvent”和“disableEvent”,没有区别的“EventEnum”,可以在只有一个事件可以触发时使用。
PoshRuntime
Listener |
| getMiddlewareConditionVariable : var |
| --------------------------------------> |
| ConditionListener(var) | ConditionListener
| ----------------------------------------+-----------------> |
| wait() : vector<uint64_t> | |
| ----------------------------------------+-----------------> |
User Listener Triggerable
| attachEvent() | |
| ------------------> | TriggerHandle |
| | create | |
| | ---------> | |
| | enableEvent(std::move(TriggerHandle)) |
| | -----------+--------------------------------------> |
ConditionListener.wait()
调用返回并检索所有信号通知的列表。相应的事件回调被调用。Triggerable TriggerHandle ConditionNotifier ConditionListener Listener Event_t
| trigger() | | | wait() : notificationIds | |
| -------------> | notify() | | <------------------------- | |
| | -------------> | .... unblocks .... | blocks | exeuteCallback() |
| | | | | ------------------------> |
| | | | | m_events[notificationId] |
resetCallback从侦听器中删除触发器
Triggerable TriggerHandle Listener Event_t
| ~TriggerHandle | | |
| ----------------> | removeTrigger() | |
| | ----------------> | reset() |
| | via resetCallback | ------------> |
Listener Event_t Triggerable
| ~Event_t() | |
| -----------> | invalidateTrigger() |
| | -----------------------> |
| | via invalidationCallback |
问题: Triggerable应该能够在不了解这些类的情况下通知Listener/WaitSet,这样就可以防止循环依赖。此外,Triggerable必须能够在超出范围时删除其附加的事件。
解决方案: 依赖反转原则,创建一个双方都知道的抽象,即TriggerHandle。由Listener/WaitSet创建并附加到Triggerable,以便它可以通过具有“TriggerHandle::notify()”的底层“ConditionNotificationer”通知Listener/WaitSet。
清理任务由“m_resetCallback”执行,因此Triggerable不依赖于任何Notifyable。
“ConditionListener”和“ConditionNotificationer”是同一类的两个不同接口,状态存储在“ConditionVariableData”类中。分离的目的是只提供一侧(例如可触发) API通知Notifyable(例如侦听器),而Notifyaable只能等待事件。因此,合同体现在设计中。
问题: 由于侦听器对事件作出反应而不是声明,因此它需要知道通知它的人。
解决方案:
NotificationVector_t
从ConditionListener::wait()
返回值索引通知了他。因此,它与TriggerHandle的唯一id相同,侦听器知道哪个Triggerable通知了他。侦听器必须能够同时附加和分离事件。此外,它支持回调可以附加或分离更多的事件,或者同时分离其相应的事件。此外,Listener支持在附加/分离事件时同时调用回调。
为了实现这一点,我们创建了“Event_t”抽象,它存储在一个名为“m_events”的数组中。如果我们想附加或分离一个事件,我们可以初始化“event_t::init()”或重置“m_events”数组中的相应条目“event_t::reset()”。数组的优点是数据结构本身在运行时不会发生变化,因此它不必是线程安全的。
线程安全性必须由“Event_t”类本身来确保。由于每个并发操作都包含在“Event_t”中,我们可以将“concurrent::smart_lock”与“std::recursive_mutex”组合使用,以确保线程安全访问。
由于事件包含处理事件所需的所有内容,因此它有责任确保TriggerHandle的使用寿命。这是通过在“Event_t::reset()”中调用的“m_invalidationCallback”来完成的,以使相应Triggerable中的TriggerHandle无效。当事件分离或侦听器超出范围时,就会执行此操作。
Triggerable是一组类,其中的事件可以附加到侦听器。
可以将类的特定事件附加到侦听器,也可以在不提供事件的情况下附加该类。
其基本思想是,每当附加事件时,侦听器都会创建一个TriggerHandle,并将该TriggerHandle提供给相应的Triggerable。Triggerable然后使用TriggerHandle向侦听器通知事件。
Every Triggerable requires:
void enableEvent(iox::popo::TriggerHandle&& triggerHandle) noexcept;
void disableEvent() noexcept;
void invalidateTrigger(const uint64_t uniqueTriggerId) noexcept;
Every Triggerable requires:
enum class
which uses iox::popo::EventEnumIdentifier
as underlying type.enum class EventEnum : iox::popo::EventEnumIdentifier {
EVENT_IDENTIFIER,
ANOTHER_EVENT_IDENTIFIER,
};
void enableEvent(iox::popo::TriggerHandle&& triggerHandle, const EventEnum event) noexcept;
void disableEvent(const EventEnum event) noexcept;
void invalidateTrigger(const uint64_t uniqueTriggerId) noexcept;
侦听器使用上述方法将TriggerHandle的所有权转移到Triggerable。对于每个可连接的事件/状态,Triggerable应该有一个TriggerHandle成员。
然后,TriggerHandle用于通过Triggerable通知监听器某个事件已经发生。
iox::popo::NotificationAttorney
的朋友。可以提供对以前方法的公共访问,但用户可以调用只应由侦听器使用的方法。Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。