现在的位置: 首页 > 综合 > 正文

C 工具库3:固定大小的 obj pool

2013年11月10日 ⁄ 综合 ⁄ 共 8410字 ⁄ 字号 评论关闭

对大小固定的对象提供的对象池工具,当对内存分配的请求大小不固定时,使用其它的通用内存池.

fix_obj_pool.h

#ifndef _FIX_OBJ_POOL_H
#define _FIX_OBJ_POOL_H


struct fix_obj_pool;


/*
* obj_size:对象大小
* default_size:默认对象池大小
* align4:返回的对象地址是否需要对齐到4字节
*/
extern struct fix_obj_pool *create_pool(unsigned int obj_size,int default_size,int align4);

extern void destroy_pool(struct fix_obj_pool **pool);

/*
* 分配和回收
*/
extern void *pool_alloc(struct fix_obj_pool*);

extern void  pool_dealloc(struct fix_obj_pool*,void*);

extern unsigned int alignsize(unsigned int obj_size);

extern unsigned int get_free_size(struct fix_obj_pool *pool);

#endif

fix_obj_pool.c

#include "fix_obj_pool.h"
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

static const  char invalid_index = -1;
static const  unsigned int BLOCK_OBJ_SIZE = 128;
struct block
{
	char m_head;
	char m_tail;
	unsigned short m_freesize;
	struct block *m_next_block;
	unsigned int obj_size;//单个对象的大小
	union
	{
		char m_objs[1];
		unsigned int pad;
	};
};

inline void *block_get(struct block *_block,unsigned int index)
{
	return (void*)&_block->m_objs[_block->obj_size * index];
}

inline int  block_check(struct block *_block,void *obj)
{
	if((char*)obj < _block->m_objs || (char*)obj >= (char*)block_get(_block,BLOCK_OBJ_SIZE))
		return 0;
	return 1;
}


void block_destroy(struct block **_block)
{
	free(*_block);
	*_block = 0;
}

void block_init(struct block *_block,unsigned int obj_size)
{
	_block->m_head = 0;
	_block->m_tail = BLOCK_OBJ_SIZE-1;
	_block->m_freesize = BLOCK_OBJ_SIZE;
	_block->obj_size = obj_size;
	int i;
	for(i = 0; i < BLOCK_OBJ_SIZE-1; ++i)
	{
		char *link = (char*)block_get(_block,i);
		*link = i+1;
	}
	char *link = (char*)block_get(_block,BLOCK_OBJ_SIZE-1);
	*link = invalid_index;
	_block->m_next_block = 0;
}

struct block *block_create(unsigned int obj_size)
{
	struct block *_block = malloc(sizeof(*_block) + obj_size*BLOCK_OBJ_SIZE - sizeof(unsigned int));
	block_init(_block,obj_size);
	return _block;
}

void* block_alloc(struct block *_block)
{
	if(_block->m_head == invalid_index)
		return 0;

	char *obj = (char*)block_get(_block,_block->m_head);
	_block->m_head = *obj;

	if(_block->m_head == invalid_index)
		_block->m_tail = invalid_index;		
	*obj = invalid_index;
	--_block->m_freesize;
	return (void*)obj;
}

inline unsigned int block_get_obj_index(struct block *_block,void* obj)
{
	unsigned int offset = (char*)obj - _block->m_objs;
	return offset/_block->obj_size;
}

void block_dealloc(struct block *_block,void* obj)
{
	assert(block_check(_block,obj));
	char *link = (char *)obj;
	*link = invalid_index;
	char index = (char)block_get_obj_index(_block,obj);
	if(_block->m_tail == invalid_index)
	{
		_block->m_head = index;
	}
	else
	{
		*(char*)block_get(_block,_block->m_tail) = index;	
	}
	_block->m_tail = index;
	++_block->m_freesize;
}

inline unsigned char block_getfreesize(struct block *_block)
{
	return _block->m_freesize;
}

inline void block_SetNextBlock(struct block *_block,struct block *next)
{
	_block->m_next_block = next;
}

inline struct block *block_GetNext(struct block *_block)
{
	return _block->m_next_block;
}

inline char *block_GetLastAddr(struct block *_block)
{
	return (char*)block_get(_block,BLOCK_OBJ_SIZE-1);
}

struct chunk
{
	struct block *m_head;
	struct block *m_tail;
	unsigned int m_freesize;
	unsigned int obj_size;
	unsigned int block_count;
	unsigned int block_size;
	struct chunk *m_next;
	struct block m_blocks[1];
};

inline struct block *chunk_get(struct chunk *_chunk,unsigned int index)
{
	char *tmp = (char*)_chunk->m_blocks;
	return (struct block *)&tmp[_chunk->block_size*index];
}

void chunk_init(struct chunk *_chunk,unsigned int block_count,unsigned int block_size,unsigned int obj_size)
{
	_chunk->m_freesize = block_count*BLOCK_OBJ_SIZE;
	_chunk->block_size = block_size;
	_chunk->block_count = block_count;
	unsigned int i;
	for(i = 0; i < block_count; ++i)
	{
		block_init(chunk_get(_chunk,i),obj_size);
	}
	for(i = 0; i < block_count-1; ++i)
	{
		block_SetNextBlock(chunk_get(_chunk,i),chunk_get(_chunk,i+1));
	}
	block_SetNextBlock(chunk_get(_chunk,block_count-1),0);
	_chunk->m_head = chunk_get(_chunk,0);
	_chunk->m_tail = chunk_get(_chunk,block_count-1);
	_chunk->m_next = 0;
}

struct chunk *chunk_create(unsigned int block_count,unsigned int obj_size)
{
	unsigned int block_size = sizeof(struct block) + obj_size * BLOCK_OBJ_SIZE - sizeof(unsigned int);
	unsigned int chunk_size = block_size*block_count;
	struct chunk *_chunk = malloc(sizeof(*_chunk) + chunk_size - sizeof(_chunk->m_blocks));
	chunk_init(_chunk,block_count,block_size,obj_size);
	return _chunk;
}

void chunk_destroy(struct chunk **_chunk)
{
	free(*_chunk);
	*_chunk = 0;
}

void* chunk_alloc(struct chunk *_chunk)
{

	if(!_chunk->m_head)
		return 0;
	void *ret = block_alloc(_chunk->m_head);
	if(block_getfreesize(_chunk->m_head) == 0)
	{
		struct block *next = block_GetNext(_chunk->m_head);
		block_SetNextBlock(_chunk->m_head,0);
		if(!next)
			_chunk->m_head = _chunk->m_tail = 0;
		else
			_chunk->m_head = next;
	}
	--_chunk->m_freesize;
	return ret;				
}

inline int chunk_check(struct chunk *_chunk,void *obj)
{
	if((char*)obj < (char*)_chunk->m_blocks || (char*)obj >= (char*)chunk_get(_chunk,_chunk->block_count))
		return 0;
	return 1;	
}

void chunk_dealloc(struct chunk *_chunk,void* obj)
{
	assert(chunk_check(_chunk,obj));
	int index = (int)(((char*)obj - (char*)&_chunk->m_blocks[0])/_chunk->block_size);
	block_dealloc(chunk_get(_chunk,index),obj);
	
	if(block_getfreesize(chunk_get(_chunk,index)) == 1)
	{
		if(!_chunk->m_tail)
		{
			_chunk->m_head = chunk_get(_chunk,index);
		}
		else
		{
			block_SetNextBlock(_chunk->m_tail,chunk_get(_chunk,index));
		}
		_chunk->m_tail = chunk_get(_chunk,index);
	}
	++_chunk->m_freesize;
}

inline unsigned int chunk_GetFreeSize(struct chunk *_chunk)
{
	return _chunk->m_freesize;
}

inline char *chunk_GetBlocksAddr(struct chunk *_chunk)
{
	return (char*)_chunk->m_blocks;
}

inline char *chunk_GetLastAddr(struct chunk *_chunk)
{
	return (char*)block_GetLastAddr(chunk_get(_chunk,_chunk->block_count-1));
}

inline void chunk_SetNext(struct chunk *_chunk, struct chunk * next)
{
	_chunk->m_next = next;
}

inline struct chunk *chunk_GetNext(struct chunk *_chunk)
{
	return _chunk->m_next;
}

#define DEFAULT_CHUNK_COUNT 128 //当chunk数量大于此值时将采用动态分配
struct fix_obj_pool
{
	struct chunk *m_lastDeAlloc;
	struct chunk *m_head;
	struct chunk *m_tail;
	struct chunk **ptr_chunk;
	unsigned int  chunk_count;
	unsigned int  obj_size;
	int           default_size;
	struct chunk *chunks[DEFAULT_CHUNK_COUNT];
};

unsigned int alignsize(unsigned int obj_size)
{
	if(obj_size % 4 > 0)
		obj_size = (obj_size / 4) * 4 + 4;
	return obj_size;
}


struct fix_obj_pool *create_pool(unsigned int obj_size,int default_size,int align4)
{
	//将default_size规整为128的倍数
	if(default_size <= 0)
		default_size = BLOCK_OBJ_SIZE;
	else
	{
		if(default_size % BLOCK_OBJ_SIZE > 0)
			default_size = (default_size / BLOCK_OBJ_SIZE) * BLOCK_OBJ_SIZE + BLOCK_OBJ_SIZE;
	}

	struct fix_obj_pool *pool = malloc(sizeof(*pool));
	if(pool)
	{
		if(align4)
			obj_size = alignsize(obj_size);
		struct chunk *_chunk = chunk_create(default_size/BLOCK_OBJ_SIZE,obj_size);
		pool->m_lastDeAlloc = 0;
		pool->m_head = pool->m_tail = _chunk;
		pool->chunk_count = 1;
		pool->ptr_chunk = pool->chunks;
		pool->ptr_chunk[0] = _chunk;
		pool->obj_size = obj_size;
		pool->default_size = default_size;
	}
	return pool;
	
}

void destroy_pool(struct fix_obj_pool **pool)
{
	unsigned int i = 0;
	for( ; i < (*pool)->chunk_count; ++i)
		chunk_destroy(&((*pool)->ptr_chunk[i]));
	if((*pool)->ptr_chunk != (*pool)->chunks)
		free((*pool)->ptr_chunk);
	free(*pool);
}


void* pool_alloc(struct fix_obj_pool *pool)
{

	void *ret = chunk_alloc(pool->m_head);
	if(chunk_GetFreeSize(pool->m_head) == 0)
	{
		pool->m_head = chunk_GetNext(pool->m_head);
		if(!pool->m_head)
		{
			//没有空间了,扩展新的块
			struct chunk *_chunk = chunk_create(pool->default_size/BLOCK_OBJ_SIZE,pool->obj_size);
			if(!_chunk)
				return 0;
			pool->m_head = pool->m_tail = _chunk;
			pool->chunk_count++;
			if(pool->chunk_count > DEFAULT_CHUNK_COUNT)
			{
				struct chunk **tmp = malloc(sizeof(*tmp)*pool->chunk_count);
				int i = 0;
				for( ; i < pool->chunk_count - 1;++i)
					tmp[i] = pool->ptr_chunk[i];
				tmp[pool->chunk_count - 1] = _chunk;
				
				if(pool->ptr_chunk != pool->chunks)
					free(pool->ptr_chunk);
				pool->ptr_chunk = tmp;
			}
			
			//对所有的chunk按其地址顺序排序
			unsigned int size = pool->chunk_count;
			int i = size-2;
			for( ; i >= 0; --i)
			{
				if(pool->m_head < pool->ptr_chunk[i])
				{
					struct chunk *tmp = pool->ptr_chunk[i];
					pool->ptr_chunk[i] = pool->m_head;
					pool->ptr_chunk[i+1] = tmp;
				}
				else
				{
					pool->ptr_chunk[i+1] = pool->m_head;
					break;
				}
			}
		}
	}
	return ret;	
}

struct chunk *BinSearch(struct fix_obj_pool *pool,void *obj)
{
	int beg = 0;
	int end = (int)pool->chunk_count;
	int len = end - beg;
	while(len > 0)
	{
		int mid = beg + len/2;
		
		if(chunk_check(pool->ptr_chunk[mid],obj) == 1)
			return pool->ptr_chunk[mid];
		else if((char*)obj > chunk_GetBlocksAddr(pool->ptr_chunk[mid]))
			beg = mid + 1;
		else
			end = mid - 1;
		len = end - beg;
	}
	if(chunk_check(pool->ptr_chunk[beg],obj) == 1)
		return pool->ptr_chunk[beg];
	return 0;
}

void pool_dealloc(struct fix_obj_pool *pool,void* obj)
{
	struct chunk *_chunk = pool->m_lastDeAlloc;
	if(!_chunk || chunk_check(_chunk,obj) == 0)
		_chunk = BinSearch(pool,obj);
	if(_chunk)
	{
		chunk_dealloc(_chunk,obj);
		if(chunk_GetFreeSize(_chunk) == 1)
		{
			if(pool->m_head)
			{
				chunk_SetNext(pool->m_tail,_chunk);
				pool->m_tail = _chunk;
			}
			else
				pool->m_head = pool->m_tail = _chunk;
		}
		pool->m_lastDeAlloc = _chunk;
	}
}

unsigned int get_free_size(struct fix_obj_pool *pool)
{
	unsigned int totalsize = 0;
	int i = 0; 
	for( ; i < pool->chunk_count; ++i)
	{
		totalsize += chunk_GetFreeSize(pool->ptr_chunk[i]);
	}
	return totalsize;
}

抱歉!评论已关闭.