高并发内存池(4)-TLS:Thread Local Storage
高并发内存池(4)-TLS:Thread Local Storage
每个线程都有哈希桶,哈希桶里面有自由链表
进程里面也会有多个线程,怎么解决序号问题,如果同时来创建,也会遇到锁的问题,这时候要借助TLS
线程局部存储(TLS),是一种变量的存储方法,这个变量在它所在的线程内是全局可访问的,但是不能被其他线程访问到,这样就保持了数据的线程独立性。而熟知的全局变量,是所有线程都可以访问的,这样就不可避免需要锁来控制,增加了控制成本和代码复杂度。
目前使用TLS的方法有多种,POSIX的pthread.h提供了一组API来实现此功能
int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));
int pthread_key_delete(pthread_key_t key);
void *pthread_getspecific(pthread_key_t key);
int pthread_setspecific(pthread_key_t key, const void *value);
除了API的方式,GCC的编译器也支持语言级别的用法,这样比用API调用,更简单
__thread int i;
extern __thread struct state s;
static __thread char *p
使用GCC编译级别支持的方式来实现TLS
#include<iostream>
#include<pthread.h>
#include<unistd.h>using namespace std;
__thread int iVar = 100;void* Thread1(void *arg)
{iVar += 200;cout<<"Thead1 Val : "<<iVar<<endl;
}void* Thread2(void *arg)
{iVar += 400;sleep(1);cout<<"Thead2 Val : "<<iVar<<endl;
}int main()
{pthread_t pid1, pid2;pthread_create(&pid1, NULL, Thread1, NULL);pthread_create(&pid2, NULL, Thread2, NULL);pthread_join(pid1, NULL);pthread_join(pid2, NULL);return 0;
}
我们这样写:(采用静态库,动态还需要调用函数)
static _declspec(thread) ThreadCache* pTLSThreadCache = nullptr;
我们创建一个头文件去封装:
#pragma once#include "Common.h"
#include "ThreadCache.h"
#include "ObjectPool.h"//申请空间
static void* ConcurrentAlloc(size_t size)
{//如果大于最大的存储空间if (size > MAX_BYTES){//向上对齐取空间size_t alignSize = SizeClass::RoundUp(size);}// 通过TLS 每个线程无锁的获取自己的专属的ThreadCache对象else{pTLSThreadCache = new ThreadCache;}//返回所需要申请的空间return pTLSThreadCache->Allocate(size);
}//释放空间
static void ConCurrentFree(void* ptr)
{}
还要做测试:
#include "ConcurrentAlloc.h"void Alloc1()
{for (size_t i = 0; i < 5; ++i){void* ptr = ConcurrentAlloc(6);}
}void Alloc2()
{for (size_t i = 0; i < 5; ++i){void* ptr = ConcurrentAlloc(7);}
}void TLSTest()
{std::thread t1(Alloc1);//等待线程执行完成。t1.join();std::thread t2(Alloc2);//等待线程执行完成。t2.join();
}
还有释放内存的过程:
//释放内存
void ThreadCache::Deallocate(void* ptr, size_t size)
{//判断指针是否为空assert(ptr);//判断内存是否为空assert(size <= MAX_BYTES);// 找对映射的自由链表桶,对象插入进入size_t index = SizeClass::Index(size);_freeLists[index].Push(ptr);
}