1

在数字信号采集系统中,通常一个线程将数据推送到系统中的观察者。从Wikipedia/Observer_pattern多线程观察器的设计模式

例如:

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

当例如来自例如用户的动作一个GUI线程需要数据停止流动,你想打破主题观察者连接,甚至将观察者全部处理掉。

有人可能会说:你应该停止数据源,然后等待一个标记值来处理连接。但是这会在系统中产生更多的延迟。

当然,如果数据抽取线程刚刚要求观察者的地址,它可能会发现它正在向被销毁的对象发送消息。

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

+0

我在这里很困惑。你想避免什么?你是在谈论一个线程想要注销一个观察者的情况,但另一个线程正在迭代所有观察者? – 2008-09-19 16:43:18

+0

我不知道你实现了`IObserver`的具体类是什么,但如果“更新”的意思是“做任何你需要做的事情来使自己更新数据源”,那么处置对象的正确行为将是默默无闻。如果有一个对象与每个观察者相关联,表明它是否应该继续接收订阅,并且如果抽吸对象具有标志,该标志指示自从上次扫描它们以来是否有任何此类对象请求取消订阅,则抽取线程可以轮询对象以取消抽取需要的时候。 – supercat 2013-01-27 22:17:17

回答

2

如果您希望让数据源始终处于并发的安全状态,那么您至少应该有一个始终安全的指针,供他使用。 因此Observer对象的生命周期应该在数据源之前没有结束。

这可以通过只添加观察者,但从不删除它们来完成。 你可以让每个观察者不是自己做核心实现,而是让它把这个任务委托给一个ObserverImpl对象。 您可以锁定对此impl对象的访问权限。这没什么大不了的,它只是意味着在观察者忙于使用ObserverImpl对象的情况下,GUI退订程序会被阻塞一段时间。如果GUI响应性成为问题,那么可以使用某种并发作业队列机制,并将推送到其上的取消订阅作业。 (如Windows中的PostMessage)

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

如果你想避免堆叠只包含虚拟物体的Observer对象,你必须做一些记账工作,但这可能归结为一些微不足道的事情,比如持有指向他需要的Observer对象的指针的对象。

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

0

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

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