2025/12/29 4:06:31
网站建设
项目流程
dw8 php做购物网站教程,动态的网站怎么做,中国十大品牌策划机构,建设银行北京招聘网站ResourcePool
1. 核心设计理念
ResourcePool 实现了一个基于智能指针自定义删除器#xff08;Deleter#xff09;机制的高性能对象池。
其核心思想是#xff1a;当用户从池中获取对象时#xff0c;得到的是一个 std::shared_ptr。当这个智能指针引用计数归零#xff08;离…ResourcePool1. 核心设计理念ResourcePool实现了一个基于智能指针自定义删除器Deleter机制的高性能对象池。其核心思想是当用户从池中获取对象时得到的是一个std::shared_ptr。当这个智能指针引用计数归零离开作用域时不会直接delete内存而是触发自定义删除器将对象“归还”给对象池。测试代码和使用示例在test_resourcePool.cpp。2. 类结构与关系分析代码中主要涉及三个类它们的关系如下2.1ResourcePool_lC(内部实现类)角色这是对象池的真正实体负责实际的内存管理、对象存储、分配和回收。继承继承自std::enable_shared_from_this。这是为了在创建对象时能够安全地将自身的weak_ptr传递给发出的智能指针以便对象析构时能找到回家的路。核心成员_objs:std::vectorC*存储空闲对象的栈。_busy:std::atomic_flag用于实现轻量级的自旋锁Spinlock。_alloc: 对象分配器 lambda默认使用new C()。关键行为Fail-fast 锁机制在getPtr和recycle中使用_busy.test_and_set()。如果获取锁失败说明有其他线程正在操作池它不会阻塞等待而是直接new一个新对象获取时或直接delete对象回收时。这种设计牺牲了对池大小的严格控制换取了极高的并发性能避免线程挂起。2.2ResourcePoolC(对外接口类/外观模式)角色这是用户直接使用的类充当ResourcePool_l的代理Facade或包装器。关系ResourcePool内部持有一个std::shared_ptrResourcePool_lC pool。存在的意义生命周期管理ResourcePool_l必须以shared_ptr形式存在才能使用shared_from_this()。ResourcePool隐藏了这一细节让用户可以像使用普通栈对象一样声明ResourcePool。接口转发将obtain、setSize等调用转发给内部的pool。2.3shared_ptr_impC(增强型智能指针)角色这是ResourcePool::obtain()返回的智能指针类型。继承继承自std::shared_ptrC。功能它携带了一个_quit标志atomic_bool。提供了quit()方法允许用户在持有对象期间决定该对象销毁时是归还池中还是彻底删除。构造函数中定义了核心的回收逻辑Deleter。3. 核心流程分析A. 获取对象 (obtain/getPtr)用户调用ResourcePool::obtain()。转发给ResourcePool_l::obtain()。调用ResourcePool_l::getPtr()尝试获取自旋锁_busy。成功如果_objs有库存弹出并返回否则调用_alloc()新建。释放锁。失败竞争激烈不等待直接调用_alloc()新建返回。将裸指针包装成shared_ptr_imp并将ResourcePool_l的weak_ptr传入删除器中。B. 回收对象 (智能指针析构)shared_ptr_imp引用计数归零触发删除器lambda。删除器检查weakPool.lock()是否能获取到ResourcePool_l的强引用。池已销毁直接delete ptr。池尚在调用strongPool-recycle(ptr)。ResourcePool_l::recycle(ptr)尝试获取自旋锁。成功如果池未满emplace_back入队如果池满了delete ptr。释放锁。失败竞争激烈不等待直接delete ptr。4. 类图 (Class Diagram)拥有 (shared_ptr)11创建 (Create)弱引用 (weak_ptr) 用于回收ResourcePool- std::shared_ptrResourcePool_lC poolobtain()obtain2()setSize(size)ResourcePool_l- std::vectorC* _objs- std::atomic_flag _busy- size_t _pool_size- std::weak_ptrResourcePool_l _weak_selfobtain()recycle(C* obj)-getPtr()shared_ptr_imp- std::shared_ptratomic_bool _quitquit(bool)shared_ptr_imp(...)«interface»std_enable_shared_from_this«class»std_shared_ptrC5. 总结ResourcePool 与 ResourcePool_l 的关系是Handle-Body (句柄-实体)或Proxy (代理)的关系。ResourcePool是面向用户的句柄负责管理ResourcePool_l的生命周期ResourcePool_l是实际干活的实体。性能特征极高并发使用atomic_flag实现无锁Wait-free的尝试机制遇到竞争立即降级为直接分配/释放杜绝了线程阻塞。安全性使用weak_ptr解决循环引用和悬垂指针问题。如果池先于对象销毁对象析构时会安全地自我删除。obtain vs obtain2obtain返回shared_ptr_imp功能更强支持quit()放弃回收但对象体积稍大多一个_quit指针。 *obtain2返回标准shared_ptr更轻量但无法中途控制是否放弃回收6. C6.1 ResourcePool_l类的成员_objs为什么使用vector类型而不是List在ResourcePool_l中使用std::vectorC *而不是List(或std::list)主要是出于极致性能的考虑特别是为了配合其自旋锁 (Spinlock)和Fail-fast的设计策略。1. 极小化临界区耗时 (最关键原因)ResourcePool_l使用了std::atomic_flag(_busy) 来实现一个非阻塞的自旋锁。机制如果test_and_set失败锁被占用代码不会等待而是直接降级为new或delete对象。要求为了提高从池中获取对象的成功率必须极度缩短持有锁的时间。对比两种容器的操作耗时std::vectorpop_back(): 仅仅是将内部的size计数器减 1。这是纯 CPU 指令操作耗时在纳秒级。emplace_back(): 在预留空间足够的情况下_objs.reserve已调用仅仅是将指针写入数组并size加 1。也是纳秒级。std::list/Listpop_back(): 需要释放链表节点的内存调用free或delete。内存分配器本身通常包含锁且操作耗时远高于简单的指针运算。push_back(): 需要分配新的链表节点内存调用malloc或new。结论使用vector可以将临界区缩小到仅包含几条汇编指令极大降低了多线程竞争导致“获取锁失败”的概率。2. 避免频繁的内存分配开销std::list: 每次将对象放回池中recycle都需要为链表节点本身分配一次内存每次取出对象都要释放节点内存。这违背了对象池“减少内存分配”的初衷。std::vector:代码中setSize调用了_objs.reserve(size)。在recycle中有判断if (_objs.size() _pool_size)。这意味着vector的底层数组一旦分配在运行过程中几乎永远不需要重新分配或扩容。它仅仅是在一段连续内存上移动尾部指针。3. 缓存局部性 (Cache Locality)std::vector内部存储的是C*指针数组这块内存在物理上是连续的。CPU 缓存L1/L2 Cache对连续内存的访问非常友好。std::list的节点分散在堆内存的各个角落遍历或访问时容易产生 Cache Miss。4. 语义匹配 (LIFO Stack)对象池的操作逻辑是用完放回去要用取出来。并不关心对象的顺序。代码中使用的是back()(取栈顶) 和pop_back()(出栈) 以及emplace_back()(入栈)。这实际上是一个栈 (Stack)结构。在 C 中std::vector是实现栈结构性能最好的容器比std::stack适配器更直接。