实现一个线程安全的内存池(使用线程私有数据机制TSD来实现)
2016-07-01 23:52
573 查看
本文只给出功能代码,后续文章进行内存池相关知识的简介。
请思考几个问题:
0)为什么已经有了glibc的malloc/free,为什么还实现自己的线程池?,答:后续文章简介给出。
1)线程池的优缺点是什么?,答:后续文章简介给出。
2)本文的线程池是如何使用TSD来实现线程安全的?,答:使用了TSD的主要属性:每个线程的data都有自己的内存空间,相互之间互不影响。
3)本文实现的线程安全的线程池能否做到每个线程使用线程池申请内存时无竞争和不互相影响的效果?答:能,因为TSD就是做到了每个线程之间的data无影响。
4)本文为什么没有使用mutex互斥量来实现线程池?答:为了实现线程安全。
5)能否通过使用mutex互斥量实现一个线程池?答案是:能。
6)使用mutex互斥量实现的线程池,每个线程之间申请内存时可能会出现竞争现象!
7)请使用mutex互斥量实现一个线程池?答:后续给出功能代码。
进行编译,编译成功,如下图所示:
![](https://img-blog.csdn.net/20160701235008963?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
<完>
请思考几个问题:
0)为什么已经有了glibc的malloc/free,为什么还实现自己的线程池?,答:后续文章简介给出。
1)线程池的优缺点是什么?,答:后续文章简介给出。
2)本文的线程池是如何使用TSD来实现线程安全的?,答:使用了TSD的主要属性:每个线程的data都有自己的内存空间,相互之间互不影响。
3)本文实现的线程安全的线程池能否做到每个线程使用线程池申请内存时无竞争和不互相影响的效果?答:能,因为TSD就是做到了每个线程之间的data无影响。
4)本文为什么没有使用mutex互斥量来实现线程池?答:为了实现线程安全。
5)能否通过使用mutex互斥量实现一个线程池?答案是:能。
6)使用mutex互斥量实现的线程池,每个线程之间申请内存时可能会出现竞争现象!
7)请使用mutex互斥量实现一个线程池?答:后续给出功能代码。
#ifndef __BLUESKY_THREADSAFEMEMORY_H__ #define __BLUESKY_THREADSAFEMEMORY_H__ ///编译时请执行 $g++ -c ./ThreadSafeMemory -o tsm.o -lpthread ///使用pthread_once系列函数时,编译时要添加-lpthread选项! #include <stdio.h> //for pthread_once系列函数 #include <pthread.h>//for pthread_once系列函数 #include <stdlib.h> //for glibc malloc/free #include <stddef.h> //for offsetof() #include <stdint.h> //for uint32_t and so on. #include <string.h> //for memcpy namespace BlueSky { //< memory node for buf struct node { int32_t index; uint32_t mem_size; struct node* next; char buf[0]; }; //< memory node list head for same SIZE_TYPE's node struct head { uint16_t nodes_cap; uint16_t nodes_size; uint32_t mem_size; struct node* head; struct node* tail; }; class CThreadSafeMemory { private: CThreadSafeMemory(){}; ~CThreadSafeMemory(){}; public: static void CreateMemoryPool(); static void DestroyMemoryPool(); static void* Malloc(uint32_t); static void Free(void* ptr); private: static void *proc_malloc(struct head* memory_pool, uint32_t size); static void proc_free(struct head* memory_pool, void* ptr); //< 为当前线程创建其私有数据的key static void create_memory_key(); static void free_memory_key(void* threadData); //< get size's hash value as memory-list-array's index static inline int get_index(uint32_t size); private: #define SIZE_TYPE_NUM 46 static struct head m_memory_template[SIZE_TYPE_NUM]; static pthread_key_t memory_pool_key; };//CThreadSafeMemory }//namespace BlueSky #endif
#include "ThreadSafeMemory.h" namespace BlueSky{ struct head CThreadSafeMemory::m_memory_template[SIZE_TYPE_NUM]; pthread_key_t CThreadSafeMemory::memory_pool_key; void CThreadSafeMemory::CreateMemoryPool() { //< create key(memory_pool_key) for TSD pthread_once_t once = PTHREAD_ONCE_INIT; pthread_once( &once, create_memory_key ); //< create TSD(memory_pool) for current thread struct head* memory_pool = new struct head[SIZE_TYPE_NUM]; memcpy ( memory_pool, m_memory_template, sizeof(struct head) * SIZE_TYPE_NUM ); //< bind TSD and key(memory_pool + memory_pool_key) pthread_setspecific( memory_pool_key, memory_pool ); } void CThreadSafeMemory::DestroyMemoryPool() { //< unbind TSD and key(memory_pool - memory_pool_key) pthread_key_delete ( memory_pool_key ); } void* CThreadSafeMemory::Malloc(uint32_t siz) { struct head* pool = (head*)pthread_getspecific ( memory_pool_key ); return proc_malloc(pool, siz); } void CThreadSafeMemory::Free(void* ptr) { struct head* pool = (head*)pthread_getspecific( memory_pool_key); proc_free(pool, ptr); } void* CThreadSafeMemory::proc_malloc(struct head* pool, uint32_t size) { struct node* ret = NULL; /// 情况1:申请超过256K的buf时,直接使用glibc的malloc来申请 if (size > 256 * 1024 || NULL == pool) { uint32_t len = sizeof(struct node) + size; ret = (struct node*)malloc( len ); ret->index = -1;//表示free时直接free,不放到memory_pool中 return ret->buf; } int index = get_index( size ); ret = pool[index].head; /// 情况2:从pool中取buf,有空闲buf的node,取出此node并将其buf返回给用户 if (ret) { pool[index].head = ret->next; ret->next = NULL; pool[index].nodes_size -= 1; return ret->buf; } /// 情况3:从pool中取buf,无空闲buf的ndoe, malloc一个node给用户 /// 用户free此buf时再将其放入到pool中 uint32_t len = sizeof(struct node) + pool[index].mem_size; ret = (struct node*)malloc( len ); ret->index = index; ret->mem_size = pool[index].mem_size; ret->next = NULL; return ret->buf; } void CThreadSafeMemory::proc_free(struct head* pool, void* ptr) { //获取得到buf所在struct node的起始指针(即属主node的对象指针pnode) struct node* pnode = (struct node*)((char*)ptr - offsetof(struct node, buf)); int index = pnode->index; if (index == -1) { free(pnode); return ; } bool full = pool[index].nodes_size == pool[index].nodes_cap; if (full) { free(pnode); return ; } struct head list = pool[index]; if (list.head == NULL) { list.head = pnode; list.tail = pnode; } else { list.tail->next = pnode; list.tail = pnode; } list.nodes_size += 1; return; } //< 为当前线程创建其私有数据的key void CThreadSafeMemory::create_memory_key() { //创建TSD的key时,也注册释放key的函数 pthread_key_create ( &memory_pool_key, free_memory_key ); } void CThreadSafeMemory::free_memory_key(void* pool) { struct head* mem_pool = (struct head*)pool; struct node* pnode = NULL; for (int i = 0; i < SIZE_TYPE_NUM; ++i) { struct head list = mem_pool[i]; while (list.nodes_size > 0) { pnode = list.head; list.head = pnode->next; free(pnode); pnode = NULL; list.nodes_size -= 1; } } } //< get size's hash value as memory-list-array's index inline int CThreadSafeMemory::get_index(uint32_t size) { int x = 0; int y = 1; int z = 0; if (size <= 128) { x = size - 1; y = 8; z = 0; } else if (size <= 256) { x = 16; y = z = 0; } else if (size <= 512) { x = 17; y = z = 0; } else if (size <= 1500) { x = 18; y = z = 0; } else if (size <= 64 * 1024) { x = size - 1; y = 4 * 1024; z = 19; } else { x = size - 1; y = 16 * 1024; y = 31; } return x/y + z; } }//namespace BlueSky
进行编译,编译成功,如下图所示:
<完>
相关文章推荐
- 常用简单算法
- HTTP
- 聊聊纠结了大半天的qua数据上报不一致的问题------经验:1. 思路很重要;2.map的下标操作要当心
- 能量项链
- 【源码学习之spark streaming 1.6.1 】
- uva 340 Master-Mind Hints(水题)
- javaScript的真值和假值
- C# 和 Java集合区别
- 常用的自定义View例子三(MultiInterfaceView多界面处理)
- Smarty笔记
- javafx中为一个Node加入多个Effect
- VS Code开发调试ASP.NET Core 1.0
- Handler从主线程向子线程发送消息
- BZOJ 3036 绿豆蛙的归宿
- Socket编程模式
- 弹性系数系数在水文气象中的应用及其MATLAB实现
- Oracle使用powerDesigner进行数据库设计
- 再见!我的2016上半年
- ListView的归纳与总结
- Asp.Net Core