高并发内存池 - thread cache TSL无锁访问 📅 2026/7/24 22:17:17 高并发内存池 - thread cache TSL无锁访问项目 gitee 链接 高并发内存池项目项目 github 链接 高并发内存池项目在已经实现了对齐规则和索引规则后关于 thread cache 最重要的一部分无锁访问该如何实现呢如果我们将 thread cache 定义为一个全局变量那么多个线程一定要进行竞争为了保护临界资源就一定要加锁这就会导致效率的降低那么多定义几个呢顺着这个思路往下想我们最终就想到了解决方案为每个线程分配一个 thread cache那就会产生新的问题进程和线程之间的资源是共享的一个线程也能看到另一个线程拥有的资源这样也可能导致安全问题所以是否有可能让 thread cache 成为每个线程自己的资源呢不和其他线程共享。是完全有可能的在 Linux 学习线程时线程有独自分配的栈和存储私有变量的空间只要将资源放入这部分空间即可在明确解决方法后就要去查找是否有对应的系统调用可以实现需求最终解决方法就为TSL (Thread Local Storage - 线程局部存储)。详细讲解 TSL 的文章Thread Local Storage线程局部存储TLS如此便不用添加锁资源也不再是临界资源大大提高了效率。下面正式进入代码编写阶段在这里书接上回先处理没有实现的判断自由链表为空函数十分简单只需判断FreeList中的_freelist是否为空指针就可以如果有可以释放的空间那表头一定不为空。boolEmpty(){return_freelistnullptr;}接下来实现无锁访问的逻辑核心就是让每个线程都有自己的 thread cache所以要让每个线程首先拥有一个指向 thread cache 的指针我们在ThreadCache.h中添加 TSL 变量externthread_localThreadCache*pTLSThreadCache;在ThreadCache.cpp中进行初始化thread_localThreadCache*pTLSThreadCachenullptr;那此时便有新的问题要思考清楚是在线程创建时为其创建 thread cache还是在其第一次调用函数分配内存的时候再为其创建 thread cache 呢对于编程策略可以参考成熟的商业产品它们采用的方法大都兼具效率和容错在 Linux 的内存加载中有懒加载机制在跳转动态库函数时也不会先将所有的函数加载至 GOT 表中而是采用延时绑定机制所以显而易见地我们也采用一种“懒创建”机制。在这个问题思考清楚后继续明晰下一个问题pTLSThreadCache 和 thread cache 是什么关系pTLSThreadCache是一个指向 thread cache 的指针且语法规定它不是类内成员所以是一种上层和下层的关系所以我们基于pTLSThreadCache指针的操作不能和 thread cache 在一层中我们需要新开一个文件命名为ConcurrentAlloc.h。现阶段文件结构接下来处理编程逻辑我们将pTLSThreadCache初始化的值设为了nullptr所以线程第一次调用函数分配内存时指针一定为空指针此时我们便创建ThreadCache对象将指针指向它如若不为空指针那便正常分配内存。释放内存的编程逻辑大同小异不做详细讲解详见代码实现。代码实现#pragmaonce#includeComm.h#includeThreadCache.hstaticvoid*ConcurrentAlloc(size_t size){if(pTLSThreadCachenullptr){pTLSThreadCachenewThreadCache;}returnpTLSThreadCache-Allocate(size);}staticvoidConcurrentFree(void*ptr,size_t size){assert(pTLSThreadCache);pTLSThreadCache-Deallocate(ptr,size);}至此我们已经编写完一定的代码按照模块进行测试是编程的好习惯所以可以基于目前所实现的模块进行综合测试。在测试之前一些现阶段只声明没实现却在某些部分调用的函数在函数体实现中先返回空指针或者实现直接为空代码块即可具体按照返回值进行区分。例如ThreadCache.cpp中的voidThreadCache::Deallocate(void*ptr,size_t size)//归还空间{}void*ThreadCache::FetchFromCentralCache(size_t index,size_t size)//从中心缓存获取数据{returnnullptr;}下一步便是对测试函数的编写既然我们对多线程情况进行了特殊优化尝试用多线程情况测试一下是否线程都有独自的 thread cache且对齐数和索引下标的计算是否正确添加一个测试文件UnitTest.cpp。#includeComm.h#includeConcurrentAlloc.hvoidAlloc1(){for(inti0;i5;i)void*ptrConcurrentAlloc(6);}voidAlloc2(){for(inti0;i5;i)void*ptrConcurrentAlloc(7);}intmain(){std::threadt1(Alloc1);std::threadt2(Alloc2);t1.join();t2.join();}当前文件结构调试结果分析线程 1 线程 2 可以观察到 线程1 和 线程2 的 thread cache 指向的地址确实不同所以实现了 TSL 无锁编程同时对于对齐数计算和索引计算的结果也同样正确到此为止 thread cache 的编写将先告一段落我们将先进入对于 central cache 的编写中其中的很多逻辑实现后我们才能返回来编写 thread cache。