CUDA与内存池(二):内存池指针
来源:互联网 发布:中信淘宝卡积分规则 编辑:程序博客网 时间:2024/04/30 14:52
前面的内存池只是提供了内存分配的功能。为了能方便地使用,还需要一些其它的设施。
单例
把内存池弄成单例类,用起来会比较方便。因为这样就可以在任何地方,通过类方法得到内存池的实例,即便内存池是在某个看不到的地方建立的。而且可以保证每种类型的池子只有一个。
单例类通常都这样实现:类里面有一个静态属性,存有一个实例,并且通过类方法访问这个实例。构造器保证实例只有一个。
template <typename T> class Singleton {public: // 存储一个实例 static T* instance; // 实例的访问函数 // 懒得检查instance是否非零 inline static T& get_instance() { return *instance; } inline static T* get_instance_ptr() { return instance; } // 构造的时候将自己存在类属性中 Singleton() { // 其实应当先检查一下是否已经存在,如果instance已经被初始化就死掉 instance = static_cast <T*> (this); } // 懒得写析构函数,析构的时候应当将instance清零protected: // 不得复制 Singleton(const Singleton<T>&); Singleton& operator=(const Singleton<T> &);};// 类属性的定义,给0初值template <typename T>T* Singleton<T>::instance = 0;
然后,修改一下内存池,让其继承singleton类:
template<typename T> class MemPool: public Singleton< MemPool<T> >{ //......};之后,不管在哪里就可以在任何地方通过MemPool<T>::get_instance()得到T类型的内存池实例。
指针类
直接使用内存池返回的索引,每次使用的时候还要把池子拽出来,获得对象引用,比较麻烦。所以,弄块语法糖把它包起来:
template<typename T>class MemPoolPointer {public: // 默认构造器,直接给0 MemPoolPointer():_p(0) { } // 复制构造器 MemPoolPointer(const MemPoolPointer<T>& other): _p(other._p) { } // 常用的构造器,把索引存起来 MemPoolPointer(uint64_t p):_p(p) { } // 重载“*”析值操作 inline T& operator * () const { return MemPool<T>::get_instance()[_p]; } // 重载“->”析值操作 inline T* operator -> () const { return &(MemPool<T>::get_instance()[_p]); } // 提供一个访问索引的方法 inline T* get_ptr() const { return &(MemPool<T>::get_instance()[_p]); } // 重载[],装作自己是一个数组,就像指针那样 inline T& operator [] (uint64_t i) { return MemPool<T>::get_instance()[_p+i]; } // 拷贝操作 inline MemPoolPointer<T> operator = (const MemPoolPointer<T>& other) { _p = other._p; return *this; } // 查看自己是否已定义 inline bool defined() { return _p != 0; }public: uint64_t _p;};// 比较操作符template <typename T>inline bool operator == (const MemPoolPointer<T>& a, const MemPoolPointer<T>& b){ return a._p == b._p;}template <typename T>inline bool operator < (const MemPoolPointer<T>& a, const MemPoolPointer<T>& b){ return a._p < b._p;}
使用
对这样一个系统,用起来仍然和正常的C++不太一样。这主要是因为使用整数进行索引,而不是指针,于是内置的内存管理操作符new、delete都不能使。目前,我只能想到这样用:在每个需要被manage的子类里面,都写若干个New函数,每个对应一个构造器;还有若干个NewList函数,用来产生一列对象;还有Delete、DeleteList函数,用来删除。这些函数模拟new、new []、delete、delete[]的功能。
下面这个测试展示了其用法。这是一个使用内存池的类:
class FooBar;typedef MemPoolPointer<FooBar> FooBarPtr;typedef MemPool<FooBar> FooBarPool;FooBarPool pool(5);class FooBar {public: FooBar(): foo(5),bar(10),id(id_seed++) { } ~FooBar() { std::cout<<"destroy object "<<id<<std::endl; } // 对于每个构造函数,都要人工写一个New static uint64_t New() { // 分配内存 uint64_t p = FooBarPool::get_instance().allocate(1); // 在分配的内存空间上调用构造函数 new (&pool[p]) FooBar(); return p; } static void Delete(FooBarPtr& p) { // 在对象上调用析构函数 FooBarPool::get_instance()[p._p].~FooBar(); // 释放内存 FooBarPool::get_instance().deallocate(p._p); } static int id_seed; int foo; int bar; int id;};int FooBar::id_seed = 0;
这是测试代码:
// 用来打印出内存池的状态template<typename T>void show_pool(const MemPool<T>& pool) { std::cout<<"###### show pool ######"<<std::endl; std::cout<<"# size: "<<pool.size<<std::endl; std::cout<<"# empty nodes:"<<std::endl; for (MemPoolNodeSet::const_iterator i = pool.empty_nodes.begin(); i!=pool.empty_nodes.end(); i++ ) { std::cout<<"# "<<i->first<<", length "<<i->second<<std::endl; } std::cout<<"# alloc nodes:"<<std::endl; for (MemPoolNodeSet::const_iterator i = pool.alloc_nodes.begin(); i!=pool.alloc_nodes.end(); i++ ) { std::cout<<"# "<<i->first<<", length "<<i->second<<std::endl; } std::cout<<"#######################"<<std::endl;}
// 测试程序,分配、回收若干个对象int main() { FooBarPtr obj1 = FooBar::New(); cout<<"after alloc 1 obj"<<endl; show_pool<FooBar>(pool); FooBarPtr obj2 = FooBar::New(); FooBarPtr obj3 = FooBar::New(); cout<<"after alloc 3 obj"<<endl; show_pool<FooBar>(pool); FooBar::Delete(obj1); FooBar::Delete(obj3); cout<<"after free 2 objs"<<endl; show_pool<FooBar>(pool); FooBar::Delete(obj2); cout<<"after free all objs"<<endl; show_pool<FooBar>(pool);}
运行得到结果:
after alloc 1 obj###### show pool ####### size: 5# empty nodes:# 0, length 4# alloc nodes:# 4, length 1#######################after alloc 3 obj###### show pool ####### size: 5# empty nodes:# 0, length 2# alloc nodes:# 2, length 1# 3, length 1# 4, length 1#######################destroy object 0destroy object 2after free 2 objs###### show pool ####### size: 5# empty nodes:# 0, length 3# 4, length 1# alloc nodes:# 3, length 1#######################destroy object 1after free all objs###### show pool ####### size: 5# empty nodes:# 0, length 5# alloc nodes:#######################
- CUDA与内存池(二):内存池指针
- CUDA与内存池(一):内存池
- CUDA与内存池(三):引用计数的智能指针
- 指针与内存(二)
- 【CUDA】二、内存分配函数
- [内存管理]智能指针与内存池的总结
- 变量 内存 指针(二)
- nginx源码解析(二)-内存池与内存管理ngx_pool_t
- CUDA入门(4):CUDA内存模型
- CUDA 学习(九)、CUDA 内存
- 指针与内存(一)
- 指针与内存(三)
- 内存管理与指针
- 内存单元与指针
- 指针与内存分配
- 指针与内存
- 内存与指针
- 内存与指针
- poj 2230 Watchcow
- static,inline,volatile
- Hadoop初接触
- Oracle 11g asm中不同au size下datafile的au分布初探
- taskAffinity属性
- CUDA与内存池(二):内存池指针
- Oracle动态注册
- 2011—2012年度总结
- 如何在Android中取得当前进程名
- Android数据存储(八)数据存储之Network
- geotools学习
- Silverlight与WCF之间的通信(1)SL客户端定时请求WCF服务
- Oracle动态注册
- linux 网络编程