快速业务通道

设计模式之观察者(Observer)模式与其C++通用实现(下)

作者 佚名技术 来源 程序设计 浏览 发布时间 2012-06-29
问题,有两种途径。一是使用线程安全容器,另一种是我们在BasicSubject的适当地方放置锁。我只讨论后一种情况。

为了让代码具有一定的灵活性,我们使用泛型编程中常用的Policies技术。第一步将锁类定义出来:

01.struct NullLocker{
02. inline void lock() {};
03. inline void unlock() {};
04.};
05.
06.struct CriticalSectionLocker{
07. CriticalSectionLocker() {::InitializeCriticalSection(&cs_);}
08. ~CriticalSectionLocker() {::DeleteCriticalSection(&cs_);}
09. inline void lock() {::EnterCriticalSection(&cs_);}
10. inline void unlock() {::LeaveCriticalSection(&cs_);}
11.private:
12. CRITICAL_SECTION cs_;
13.};

前者为空锁,用于单线程环境中。后者借助Windows平台中的临界区实现进程内的锁语义。你也可以再增加进程间的锁语义。

接着便是将我们的BasicSubject类修改成如下样子:

01.template <
02. class ObserverT,
03. class LockerT = NullLocker,
04. class ContainerT = std::list<ObserverT *>
05.>
06.class BasicSubject : protected LockerT {
07.public:
08. inline void addObserver(ObserverT &observer) {
09. lock();
10. observers_.push_back(&observer);
11. unlock();
12. }
13.
14. inline void removeObserver(ObserverT &observer) {
15. lock();
16. ...
17. unlock();
18. }
19.
20.protected:
21. template <typename ReturnT>
22. inline void notifyAll(ReturnT (ObserverT::*pfn)()) {
23. lock();
24. for (ContainerT::iterator it = observers_.begin(), itEnd = observers_.end(); it != itEnd; ++it)
25. ((*it)->*pfn)();
26. unlock();
27. }
28. ...
29.};

默认的锁类是NullLocker,也就是运行在单线程环境中。需要工作在多线程中时可像这样使用:

class Widget : protected BasicSubject<MouseListener, CriticalSectionLocker> {...};

(三)更新方法修改观察者链表

想像一下当观察者在接收到通知而立即修改主题中的观察者链表时会发生什么?因为主题是通过对已注册的观察者链表迭代而逐个通知观察者的相应更新方法的,换句话说,在迭代进行中观察者就去修改观察者链表。这个问题类似于这样的代码设计:

01.std::list<int> is = ...
02.for (std::list<int>::iterator it = is.begin(); it != is.end(); ++it) {
03. is.erase(std::remove(is.begin(), is.end(), 2), is.end());
04.}

危险!迭代器在链表被修改后有可能失效。

也许你会疑虑,在使用了(二)中所提的锁机制之后不就不会有此问题了吗?实际情况是,锁对于此类问题没有任何作用。

解决此类问题的最好办法是使用不会因容器本身被修改而促使迭代器失效的容器。然而,就目前来说,标准STL库中的所有容器都不属此类。因此,我们有必要花点心思处理此类问题。

当链表处于被迭代过程中时,对链表的修改动作先被记录下来,等到链表迭代完毕后再回过头执行先前记录下来的修改动作,如果对链表的修改动作不是发生在迭代过程中,就按普通方式处理。依据此思想,代码可像这样实现:

01.template <
02. ...
03.>
04.class BasicSubject : protected LockerT
05.{
06.public:
07. BasicSubject() : withinLoop_(false) {}
08.
09. void addObserver(ObserverT &observer) {
10. lock();
11. if (withinLoop_)
12. modifyActionBuf_.insert(std::make_pair(true, &observer));
13. els

凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

分享到: 更多

Copyright ©1999-2011 厦门凌众科技有限公司 厦门优通互联科技开发有限公司 All rights reserved

地址(ADD):厦门软件园二期望海路63号701E(东南融通旁) 邮编(ZIP):361008

电话:0592-5908028 传真:0592-5908039 咨询信箱:web@lingzhong.cn 咨询OICQ:173723134

《中华人民共和国增值电信业务经营许可证》闽B2-20100024  ICP备案:闽ICP备05037997号