1

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

来自Wikipedia/Observer_pattern的示例:

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

例如,当来自例如 GUI 线程的用户操作要求数据停止流动时,您希望中​​断主体与观察者的连接,甚至一起处置观察者。

有人可能会争辩说:您应该停止数据源,并等待一个哨兵值来处理连接。但这会在系统中产生更多的延迟。

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

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

4

2 回答 2

2

如果您希望数据源始终处于并发安全的一侧,您应该至少有一个指针始终可以安全地供他使用。所以 Observer 对象的生命周期应该不会在数据源的生命周期之前结束。

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

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

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

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

于 2008-09-19T15:37:01.060 回答
0

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

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

于 2008-09-17T11:18:56.603 回答