在数字信号采集系统中,通常通过一个线程将数据推送到系统中的观察者中。

示例来自 维基百科/Observer_pattern:

foreach (IObserver observer in observers)
    observer.Update(message);

当例如来自例如的用户操作GUI 线程要求数据停止流动,您想要中断主体-观察者连接,甚至完全处置观察者。

有人可能会争辩说:您应该停止数据源,并等待哨兵值来处理连接。但这会导致系统出现更多延迟。

当然,如果数据泵线程刚刚请求观察者的地址,它可能会发现它正在向被破坏的对象发送消息。

有人创建了一个“官方”设计模式来应对这种情况吗?他们不应该吗?

有帮助吗?

解决方案

如果你想让数据源始终处于并发安全的一面,那么你应该至少有一个始终安全供他使用的指针。因此,观察者对象的生命周期应该不会早于数据源的生命周期。

这可以通过仅添加观察者而不删除它们来完成。您可以让每个观察者本身不执行核心实现,而是将此任务委托给 ObserverImpl 对象。您锁定对此 impl 对象的访问。这没什么大不了的,它只是意味着 GUI 取消订阅者会被阻塞一段时间,以防观察者忙于使用 ObserverImpl 对象。如果 GUI 响应能力成为问题,您可以使用某种并发作业队列机制,并将取消订阅作业推送到其上。(就像 Windows 中的 PostMessage 一样)

取消订阅时,您只需用核心实现替换虚拟实现即可。同样,此操作应该获取锁。这确实会引入一些等待数据源的过程,但由于它只是一个[锁定 - 指针交换 - 解锁],你可以说这对于实时应用程序来说已经足够快了。

如果您想避免堆叠仅包含虚拟对象的观察者对象,则必须进行某种簿记,但这可能会归结为一些琐碎的事情,例如持有指向他需要的列表中观察者对象的指针的对象。

优化 :如果您还保持实现(真实的 + 虚拟的)与观察者本身一样长,那么您可以在没有实际锁定的情况下执行此操作,并使用 InterlockedExchangePointer 之类的东西来交换指针。最坏的情况 :当指针交换时,委托调用正在进行 --> 没什么大不了的,所有对象都保持活动状态并且委托可以继续。下一个委托调用将是新的实现对象。(当然,除非有任何新的交换)

其他提示

您可以向所有观察者发送一条消息,通知他们数据源正在终止,并让观察者将自己从列表中删除。

作为对评论的回应,主体-观察者模式的实现应该允许动态添加/删除观察者。在 C# 中,事件系统是主体/观察者模式,其中观察者使用以下方式添加 event += observer 并使用删除 event -= observer.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top