随笔-157  评论-223  文章-30  trackbacks-0
   在《基于stl序列容器实现的通用集合类》一文中,已经讲到了具体实现,近来因再次用到它又改进完善了,主要体现在以下几点:1)增加了查找操作方法,支持按值类型和谓词条件两种方式。2)增加重载了按值类型和谓词条件2种方式删除元素的方法。3)增加了2个模板参数以支持线程安全,一个是线程模型模板类,一个是互斥锁类,使用loki库来实现,因此所有方法现在都是线程安全的,当需要在多线程环境使用时,注意这里是对象级别锁而不是类级别锁,只需定义loki中的宏LOKI_OBJECT_LEVEL_THREADING即可;当在单线程环境使用时,LOKI_CLASS_LEVEL_THREADING和LOKI_OBJECT_LEVEL_THREADING两个宏都不要定义。代码如下:
  1#ifndef _STL_COLLECTION_H
  2#define _STL_COLLECTION_H
  3
  4#include <memory>
  5#include <vector>
  6#include <loki/Threads.h>
  7
  8  /**
  9    @class STLCollection
 10    @brief 基于STL容器(vector,list,deque)实现的数据结构通用集合类
 11
 12    * 提供以索引作为外参的以下公共通用接口
 13    *  add    --- 向前或向后增加单个元素
 14    *  insert --- 插入单个元素
 15    *  erase  --- 删除单个或多个元素
 16    *  set    --- 修改某个元素
 17    *  get    --- 获取某个元素
 18    *  find   --- 查找某个元素
 19    *  front  --- 获取第一个元素
 20    *  back   --- 获取最后一个元素
 21*/

 22
 23template<typename T,
 24         template <classclass> class ThreadModel = LOKI_DEFAULT_THREADING,
 25         class MutexPolicy = LOKI_DEFAULT_MUTEX,
 26         template<class T,class U > class C = std::vector,
 27         template <class T> class U = std::allocator
 28         >
 29class STLCollection : public C<T,U<T> >
 30{
 31    typedef U<T> Allocator;
 32    typedef C<T,Allocator> base;
 33    typedef STLCollection<T,ThreadModel,MutexPolicy,C,U> self;
 34
 35public:
 36    STLCollection()
 37    {
 38    }

 39    explicit STLCollection(const Allocator& al)
 40        :base(al)
 41    {
 42    }

 43    explicit STLCollection(size_t n)
 44        :base(n)
 45    {
 46    }

 47    STLCollection(size_t n,const T& t)
 48        :base(n,t)
 49    {
 50    }

 51    STLCollection(size_t n,const T& t,const Allocator& al)
 52        :base(n,t,al)
 53    {
 54    }

 55    STLCollection(const STLCollection& right)
 56        :base(right)
 57    {
 58    }

 59
 60    template<class InputIterator>
 61    STLCollection(InputIterator first,InputIterator last)
 62        :base(first,last)
 63    {
 64    }

 65
 66    template<class InputIterator>
 67    STLCollection(InputIterator first,InputIterator last,const Allocator& al)
 68        :base(first,last,al)
 69    {
 70    }

 71    ~STLCollection()
 72    {
 73        typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
 74    }

 75
 76public:
 77    using base::erase;
 78    using base::insert;
 79    using base::front;
 80    using base::back;
 81
 82    void add(const T& t,bool append = true)
 83    {
 84        typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
 85        if (append)
 86            base::insert(base::end(),t);
 87        else
 88            base::insert(base::begin(),t);
 89    }

 90    void insert(size_t index,const T& t)
 91    {
 92        typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
 93        insert_impl(index,t,typename std::iterator_traits<typename base::iterator>::iterator_category());
 94    }

 95
 96    void erase(size_t index)
 97    {
 98        typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
 99        erase_impl(index,typename std::iterator_traits<typename base::iterator>::iterator_category());
100    }

101    void erase(size_t beg,size_t end)
102    {
103        typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
104        erase_impl(beg,end,typename std::iterator_traits<typename base::iterator>::iterator_category());
105    }

106    void erase(const T& val)
107    {
108        typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
109        typename base::iterator it = std::find(base::begin(),base::end(),val);
110        if (it != base::end()) base::erase(it);
111    }

112    template<class Predicate>
113    void erase(const Predicate& Pred)
114    {
115        typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
116        typename base::iterator it = std::find_if(base::begin(),base::end(),Pred);
117        if (it != base::end()) base::erase(it);
118    }

119
120    void set(size_t index,const T& t)
121    {
122        typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
123        T* p = get(index);
124        if (p) *= t;
125    }

126
127    T* get(size_t index) 
128    {
129        typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
130        return get_impl(index,typename std::iterator_traits<typename base::iterator>::iterator_category());
131    }

132    const T* get(size_t index) const
133    {
134        typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
135        return get_impl(index,typename std::iterator_traits<typename base::iterator>::iterator_category());
136    }

137
138    T* find(const T& val,size_t* index)
139    {
140        typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
141
142        typename base::iterator it = std::find(base::begin(),base::end(),val);
143        if (it == base::end()) return NULL;
144        if (index) *index = std::distance(base::begin(),it);
145        return &it;
146    }

147    const T* find(const T& val,size_t* index) const
148    {
149        typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
150
151        typename base::const_iterator it = std::find(base::begin(),base::end(),val);
152        if (it == base::end()) return NULL;
153        if (index) *index = std::distance(base::begin(),it);
154        return &it;
155    }

156    template<class Predicate>
157    T* find(const Predicate& Pred,size_t* index)
158    {
159        typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
160
161        typename base::iterator it = std::find_if(base::begin(),base::end(),Pred);
162        if (it == base::end()) return NULL;
163        if (index) *index = std::distance(base::begin(),it);
164        return &it;
165    }

166    template<class Predicate>
167    const T* find(const Predicate& Pred,size_t* index) const
168    {
169        typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
170
171        typename base::const_iterator it = std::find_if(base::begin(),base::end(),Pred);
172        if (it == base::end()) return NULL;
173        if (index) *index = std::distance(base::begin(),it);
174        return &it;
175    }

176
177    T* front()
178    {
179        typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
180
181        if (base::empty()) return NULL;
182        return &base::front();
183    }

184    const T* front() const
185    {
186        typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
187
188        if (base::empty()) return NULL;
189        return &base::front();
190    }

191
192    T* back()
193    {
194        typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
195
196        if (base::empty()) return NULL;
197        return &base::back();
198    }

199    const T* back() const
200    {
201        typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
202
203        if (base::empty()) return NULL;
204        return &base::back();
205    }

206
207    bool is_empty() const
208    {
209        typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
210        return base::empty();
211    }

212
213private:
214    void insert_impl(size_t index,const T& t,std::random_access_iterator_tag tag)
215    {
216        if (index < base::size())
217        {
218            base::insert(base::begin()+index,t);
219        }

220    }

221    void insert_impl(size_t index,const T& t,std::input_iterator_tag tag)
222    {
223        if (index < base::size())
224        {
225            typename base::iterator it = base::begin();
226            while(index--++it;
227            base::insert(it,t);
228        }

229    }

230    void erase_impl(size_t index,std::random_access_iterator_tag tag)
231    {
232        if (index < base::size())
233        {
234            base::erase(base::begin()+index);
235        }

236    }

237    void erase_impl(size_t index,std::input_iterator_tag tag)
238    {
239        if (index < base::size())
240        {
241            typename base::iterator it = base::begin();
242            while(index--++it;
243            base::erase(it);
244        }

245    }

246    void erase_impl(size_t beg,size_t end,std::random_access_iterator_tag tag)
247    {
248        end = std::min(end,base::size());
249        if (beg < end)
250        {
251            base::erase(base::begin()+beg,base::begin()+end);
252        }

253    }

254    void erase_impl(size_t beg,size_t end,std::input_iterator_tag tag)
255    {
256        end = std::min(end,base::size());
257        if (beg < end)
258        {
259            typename base::iterator it = base::begin();
260            while(beg++ < end) it = base::erase(it);
261        }

262    }

263    T* get_impl(size_t index,std::random_access_iterator_tag tag)
264    {
265        if (index>=base::size())
266            return NULL;
267        return &(*(base::begin()+index));
268    }

269    const T* get_impl(size_t index,std::random_access_iterator_tag tag) const
270    {
271        if (index>=base::size())
272            return NULL;
273        return &(*(base::begin()+index));
274    }

275    T* get_impl(size_t index,std::input_iterator_tag tag)
276    {
277        if (index>=base::size())
278            return NULL;
279        typename base::iterator it = base::begin();
280        while (index--++it;
281        return &(*it);
282    }

283    const T* get_impl(size_t index,std::input_iterator_tag tag) const
284    {
285        if (index>=base::size())
286            return NULL;
287        typename base::const_iterator it = base::begin();
288        while(index--++it;
289        return &(*it);
290    }

291private:
292    ThreadModel<STLCollection,MutexPolicy> lock_;
293}
;
294
295#endif
   
   现在来看一下它的应用,一个网络通讯项目,由UI客户端(gsoap & c++开发)和服务端(java开发)构成,服务端已实现了一些web service的同步方法,客户端需要调用它实现相关功能,为了不阻塞界面,因此需要转化成异步方式调用,调用的结果使用PostMessage API 发自定义消息给窗口,因此发送消息方new 了一个结果的拷贝给窗口,窗口收到后再delete这个结果,但有个问题是post消息可能会丢失导致结果得不到释放,产生内存泄露。因此设计一个智能指针容器而且是线程安全的,在发消息时将结果拷贝加到容器中,在接收方处理结果后再从容器中删除它,这样就可保证无内存泄露问题了。关于智能指针容器,boost中有ptr_vector,ptr_list,ptr_set等现成的,但是它们不是按照指针本身而是指针指向的对象来对待的,也就是说你要删除其中的指针,是按照指针指向的对象来比较查找的,原因是其内部迭代器的访问作了特殊处理,因此这点不符合上面应用的需求,当然可以在指针指向的对象中做点手脚,但是这方法有点勉强,应用要的只是删除指针,而不必关心它指向的对象。为了达到目的又能最大程度地复用代码,因此改进了STLCollection,简单地实现了智能指针容器,代码如下:
 1#ifndef _PTR_CONTAINER_H
 2#define _PTR_CONTAINER_H
 3
 4#include "stl_collection.h"
 5#include <boost/smart_ptr.hpp>
 6
 7class raw_ptr_compare
 8{
 9public:
10    raw_ptr_compare(void* ptr):m_ptr(ptr)
11    {
12    }

13    bool operator()(const boost::shared_ptr<void>& sp) const
14    {
15        return sp.get()==m_ptr;
16    }

17private:
18    void* m_ptr;
19}
;
20
21typedef STLCollection<boost::shared_ptr<void> > ptr_container;
22typedef boost::weak_ptr<ptr_container> wp_ptr_container;
23
24#ifdef _LOKI_SINGLETON
25#include <loki/Singleton.h>
26
27template<class T>
28struct Loki::CreateUsingNew<boost::weak_ptr<T> >
29{
30    static boost::weak_ptr<T>* Create()
31    {
32        static boost::shared_ptr<T> sp(new T);
33        static boost::weak_ptr<T> wp = sp;
34        return &wp;
35    }

36
37    static void Destroy(boost::weak_ptr<T>* p)
38    {
39    }

40}
;
41typedef ::Loki::SingletonHolder<wp_ptr_container> SingletonSmartPointerContainer;
42#endif
43
44#endif
 
   应用的示例代码如下:   
 1//在工作线程中,执行调用同步webservice方法login
 2void login_task::Run(const volatile BOOL& bExit)
 3{
 4    assert(m_client);
 5    login_output out;
 6    if (m_client->login(*this,out))
 7    {
 8        boost::shared_ptr<void> sp(new login_output(out));
 9        boost::shared_ptr<ptr_container> sp_ptr = SingletonSmartPointerContainer::Instance().lock();
10        if (sp_ptr) 
11        {
12            sp_ptr->add(sp);
13            ::PostMessage(m_hWnd,WM_LOGIN,0,(LPARAM)sp.get());
14        }

15    }

16    else
17    {
18        ::PostMessage(m_hWnd,WM_LOGIN,1,0);
19    }

20}

21//在UI线程中,异步回调WM_LOGIN消息处理
22LRESULT Cvpn_ca_clientDlg::OnLoginCallback(WPARAM wParam,LPARAM lParam)
23{
24    if (0==wParam)
25    {
26        login_output* p_out = (login_output*)lParam;
27        boost::shared_ptr<ptr_container> sp = SingletonSmartPointerContainer::Instance().lock();
28        if (sp) 
29        {
30            sp->erase(raw_ptr_compare(p_out));
31        }

32    }

33    else if (1==wParam)
34    {
35
36    }

37    return S_OK;
38}
posted on 2011-10-21 18:43 春秋十二月 阅读(3150) 评论(1)  编辑 收藏 引用 所属分类: Opensrc

评论:
# re: 基于stl序列容器实现的通用集合类 (线程安全版)[未登录] 2011-10-21 23:26 | 菜鸟
我比较菜啊,请教个问题:

这么做后,如果接收方仍然丢失了Post过来的消息,就不会有内存泄露了?  回复  更多评论
  

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理