在前面一篇用线程私有数据TSD实现了线程间无竞争的内存池,因为每个线程都会有自己的私有key对应的私有线程池,所以每个线程之间使用的内存池不会有任何竞争。
文章地址:实现一个线程安全的内存池(使用线程私有数据机制TSD来实现)
本篇文章使用公共内存池和系统锁pthread_mutex_t进行内存池的同步,所以本篇实现的内存池因为使用了公共内存池和锁,所以当有多个线程同时申请内存时,会产生锁操作,所以比起上篇实现的线程安全的内存池这是一个缺点,请注意。
//MemoryPool.h
#ifndef __BLUESKY_MEMORYPOOL_H__
#define __BLUESKY_MEMORYPOOL_H__
///编译时请执行 $g++ -c ./MemoryPool.cpp -o mp.o -lpthread
///使用pthread_once系列函数时,编译时要添加-lpthread选项!
#include <stdio.h>
#include <pthread.h>//for pthread_mutex系列函数
#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 CMemoryPool
{
private:
CMemoryPool(){};
~CMemoryPool(){};
public:
static void CreateMemoryPool();
static void DestroyMemoryPool();
static void* Malloc(uint32_t);
static void Free(void* ptr);
static void Init();
private:
//< 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 struct head* m_memory_pool;
static pthread_mutex_t m_pool_mutex;
};//CMemoryPool
}//namespace BlueSky
#endif
//MemoryPool.cpp
#include "MemoryPool.h"
namespace BlueSky{
struct head CMemoryPool::m_memory_template[SIZE_TYPE_NUM];
struct head* CMemoryPool::m_memory_pool;
pthread_mutex_t CMemoryPool::m_pool_mutex;
#define MUTEX_LOCK \
do { \
pthread_mutex_lock(&m_pool_mutex); \
}while(0);
#define MUTEX_UNLOCK \
do {\
pthread_mutex_unlock(&m_pool_mutex); \
}while(0);
void CMemoryPool::Init()
{
m_memory_pool = NULL;
}
void CMemoryPool::CreateMemoryPool()
{
if (m_memory_pool == NULL)
{
m_memory_pool = new struct head[SIZE_TYPE_NUM];
memcpy (m_memory_pool, m_memory_template, sizeof (struct head) * SIZE_TYPE_NUM);
}
}
void CMemoryPool::DestroyMemoryPool()
{
if (m_memory_pool != NULL)
{
free(m_memory_pool);
m_memory_pool = NULL;
}
}
void* CMemoryPool::Malloc(uint32_t size)
{
struct node* ret = NULL;
/// 情况1:申请超过256K的buf时,直接使用glibc的malloc来申请
if (size > 256 * 1024 || NULL == m_memory_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 );
MUTEX_LOCK;
ret = m_memory_pool[index].head;
/// 情况2:从pool中取buf,有空闲buf的node,取出此node并将其buf返回给用户
if (ret)
{
m_memory_pool[index].head = ret->next;
ret->next = NULL;
m_memory_pool[index].nodes_size -= 1;
MUTEX_UNLOCK;
return ret->buf;
}
MUTEX_UNLOCK;
/// 情况3:从pool中取buf,无空闲buf的ndoe, malloc一个node给用户
/// 用户free此buf时再将其放入到pool中
uint32_t len = sizeof(struct node) + m_memory_pool[index].mem_size;
ret = (struct node*)malloc( len );
ret->index = index;
ret->mem_size = m_memory_pool[index].mem_size;
ret->next = NULL;
return ret->buf;
}
void CMemoryPool::Free( void* ptr)
{
struct node* pnode = (struct node*)((char*)ptr - offsetof(struct node, buf));
int index = pnode->index;
if (index == -1) {
free(pnode);
return ;
}
MUTEX_LOCK;
bool full = m_memory_pool[index].nodes_size == m_memory_pool[index].nodes_cap;
if (full) {
MUTEX_UNLOCK;
free(pnode);
return ;
}
struct head list = m_memory_pool[index];
if (list.head == NULL) {
list.head = pnode;
list.tail = pnode;
}
else {
list.tail->next = pnode;
list.tail = pnode;
}
list.nodes_size += 1;
MUTEX_UNLOCK;
return;
}
//< get size's hash value as memory-list-array's index
inline int CMemoryPool::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
(完)