C++内存池

<span style="font-size:18px;"> </span>
这几天闲来无聊,就想写一些程序模块,方便以后的调用,想来想去那就先写个内存池吧。在网上搜罗了一下,有很多资料,还有很多开源的线程池。正当时在犹豫该看开源代码还是自己写。

看到了一个通俗易懂的简介:http://www.cnblogs.com/bangerlee/archive/2011/09/01/2161437.html

想到网上有这么多资料我就不在此处罗列了:


软件结构图:


注意:在代码的实现中,可变内存放在了最后一项;

为了支持多线程操作(只支持linux平台),在代码中引入了无锁线程SCA模式,既能够保证程序的运行效率,又能够内存池能够安全运行的。

代码结构说明:

mempool.cpp 线程主体实现代码,通过指针数组和双向链表来维护内存池结构。其中可变内存大小可以动态更改。固定内存不支持动态扩张。但每个不同大小的内存池块长度,在初始化的时候可以根据需要设置不同的长度。

scalock.hpp:用于支持linux平台下的多线程。

main.cpp:测试代码。

好了废话不多说了,直接来代码简介:

  *brife:一个简单的内存池,
*1、通过预先的内存分配,来减少new和delete来提高程序的处理效率
*2、为了减少内存碎片,程序首先分配一大块内存,然后再划分成子内存片
*3、为减少难度,在程序归还的时候,并未进行内存合并
*4、为提高健壮性,可以单独申请一定数量的超过内存池预设值的大小
*5、为提高处理效率,全部采用C 来实现,C++封装
*6、支持UNIX平台下的多线程使用时需定义宏#define _LINUX_MULIT_THREAD
*7、内存池为空,返回为NULL,不阻塞

*8、该内存池不支持动态扩展
*author:zp info:zhang_int@sina.cndate:14-11-7

代码在linux平台上测试并通过:下一篇写模板线程池吧!!!

具体实现代码:

线程池头文件 mempool.h:

 

#include <malloc.h>
#include <stdio.h>
#include <string.h>
#include <iostream>

#define UNUSE_BLOCK	0
#define USE_BLOCK 	1
#define DIFF_SIZENUM 64

#define _LINUX_MULIT_THREAD

#ifdef _LINUX_MULIT_THREAD
	#include "scalock.hpp"
#endif

typedef struct							//内存池的相关属性
{
	int _max_buf;						//最大能够分配的内存
	int _maxnum_inprocess;				//超过最大值后在进程中预留的块数
	int _size_num;						//不同size 的buff种类个数,最多DIFF_SIZENUM
	int _mem_size[DIFF_SIZENUM][2];		//存放size 和size的个数,种类最多64个[0] 是block大小 [1] 是block个数
										//需要从小到大的顺序排列
	long _totalsize;					//总共分配的内存大小
} MEMINFO;

typedef struct block				//内存节点链表封装	
{
	int size;
	void*memaddr;
	int flag;						//使用还是未用的标志
	struct block* next;
	struct block* before;
}BLOCK;

typedef struct 						//pool 总结构封装
{
	int free;
	int blocknum;
	int blocksize;
	BLOCK* block_addr;
} MEMPOOL;

class mempool
{
public:

	mempool(){}
	
	~mempool();

	static mempool* getinstance();

	static bool init(MEMINFO poolinfo);	

public:

	void test_fun(int order);

	long get_totalbyte();

	int getmempoolinfo();

	BLOCK* getmemnode(int size);	

	void putmemnode(BLOCK* pblock);

	char* getlasterror();

	void mem_destroy();

private:
	
	bool mempool_init(MEMINFO poolinfo);

	long mempooltotalsize(MEMINFO& poolinfo);				//创建内存池

	bool create_mempool();

	BLOCK* create_blocklist(int blocksize, int blocknum, void* memaddr);

	BLOCK* get_maxnode(int size);						//获取内存大小超过了配置中的大小

	BLOCK* get_normalnode(int size);						//获取池中有匹配的大小
	
	
private:

	static mempool* _mempool;

	MEMPOOL* m_mempool[64];		 

	MEMINFO m_poolinfo;

	char errmsg[255];

	void* ptmpaddr;											//内存池申请的一大块连续的内存

#ifdef _LINUX_MULIT_THREAD
	scalock _synlock;
#endif	
	
};

#endif
 2、mempool.cpp
<span style="white-space:pre">	</span>通过指针数组和双向链表来维护内存该内存池
<pre name="code" class="cpp">#include "mempool.h"


mempool* mempool::_mempool = NULL;

mempool::~mempool()
{
	//free(ptmpaddr);
	
	for (int i=0; i<m_poolinfo._size_num; i++)
	{
		BLOCK* pnode = m_mempool[i]->block_addr;
		
		BLOCK* pnext;

		while (pnode)
		{
			pnext = pnode->next;

			free(pnode);

			pnode = pnext;
		}
	}	
}

bool mempool::init(MEMINFO poolinfo)
{
	_mempool = new mempool;

	return _mempool->mempool_init(poolinfo);	
}

bool mempool::mempool_init(MEMINFO poolinfo)
{	
	m_poolinfo = poolinfo;

	if (mempooltotalsize(m_poolinfo) == 0)
	{
		return false;
	}

	return create_mempool();
}

mempool* mempool::getinstance()
{
	return _mempool;
}

char* mempool::getlasterror()
{
	return errmsg;
}
void mempool::mem_destroy()
{
	delete _mempool;
	
	_mempool = NULL;
}

long mempool::get_totalbyte()
{
	return m_poolinfo._totalsize;	
}


void mempool::test_fun(int order)
{
	if (order == -1)
	{
		for (int i=0; i<m_poolinfo._size_num; i++)
		{
			std::cout<<"order:"<<i<<" size:"<<m_mempool[i]->blocksize<<" free:"<<m_mempool[i]->free<<" num:"<<m_mempool[i]->blocknum<<std::endl;

			BLOCK* node = m_mempool[i]->block_addr;
			
			BLOCK* before;

			while (node)
			{
				std::cout<<node->size<<" ";

				before = node;

				node = node->next;
			}
			std::cout<<std::endl;

			node = before;
			
			while (node)
			{
				std::cout<<node->size<<" ";
				node = node->before;
			}
			std::cout<<std::endl;
		}
	}
	else
	{
		std::cout<<"order:"<<order<<" size:"<<m_mempool[order]->blocksize<<" free:"<<m_mempool[order]->free<<" num:"<<m_mempool[order]->blocknum<<std::endl;

		BLOCK* node = m_mempool[order]->block_addr;
		BLOCK* before;
		while (node)
		{
			std::cout<<node->size<<" ";
			before = node;
			node = node->next;			
		}
		std::cout<<std::endl;
		node = before;
		while (node)
		{
			std::cout<<node->size<<" ";
			node = node->before;
		}
		std::cout<<std::endl;
	}
}


BLOCK* mempool::getmemnode(int size)
{
	BLOCK* pmemblock;
	
#ifdef _LINUX_MULIT_THREAD
	_synlock.sca_lock();
#endif

	if (size > m_poolinfo._max_buf)				//超过了最大值
	{
		pmemblock = get_maxnode(size);
	}
	else
	{
		pmemblock = get_normalnode(size);
	}
	
#ifdef _LINUX_MULIT_THREAD
		_synlock.sca_unlock();
#endif

	return pmemblock;

}	

BLOCK* mempool::get_maxnode(int size)
{
	int searchflag = 0;

	//max-list 可用个数为0
	if (m_mempool[m_poolinfo._size_num]->free != 0)
	{
		BLOCK* pnode = m_mempool[m_poolinfo._size_num]->block_addr;

		while (pnode)
		{
			if (pnode->size>=size&&pnode->flag == UNUSE_BLOCK)
			{
				pnode->flag = USE_BLOCK;

				searchflag = 1;
				
				return pnode;
			}
			pnode = pnode->next;
		}			
	}
	if (searchflag == 0)
	{		
		if (m_mempool[m_poolinfo._size_num]->blocknum<m_poolinfo._maxnum_inprocess)
		{
			BLOCK* pcur = (BLOCK*)malloc(sizeof(BLOCK));
			
			pcur->size = size;		
			
			pcur->memaddr = malloc(size);
			
			pcur->flag = USE_BLOCK;
			
			pcur->next = NULL;

			if (NULL == m_mempool[m_poolinfo._size_num]->block_addr)
			{
				pcur->before = NULL;

				m_mempool[m_poolinfo._size_num]->block_addr = pcur;	
			}
			else
			{
				BLOCK* pnode = m_mempool[m_poolinfo._size_num]->block_addr;
				
				while (pnode->next)
				{
					pnode = pnode->next;
				}
				pnode->next = pcur;
				
				pcur->before = pnode;
			}
			m_mempool[m_poolinfo._size_num]->blocknum++;

			m_mempool[m_poolinfo._size_num]->blocksize++;

			//test_fun(m_poolinfo._size_num);
			
			return pcur;
		}
		//挂载个数已经大于_maxnum_inprocess
		//遍历max list 删除其中一个未用的node,重新生成一个node
		BLOCK* pnode = m_mempool[m_poolinfo._size_num]->block_addr;

		while (pnode)
		{
			/*if (m_mempool[m_poolinfo._size_num]->blocknum == 2)
			{
				test_fun(m_poolinfo._size_num);
			}*/
			
			if (pnode->flag == UNUSE_BLOCK)
			{
				BLOCK* pcur = (BLOCK*)malloc(sizeof(BLOCK));
			
				pcur->size = size;		
				
				pcur->memaddr = malloc(size);
				
				pcur->flag = USE_BLOCK;	

				BLOCK* pbefore = pnode->before;

				if (pbefore != NULL)
				{
					pbefore->next = pcur;
				}
				else		//更新头结点
					m_mempool[m_poolinfo._size_num]->block_addr = pcur;

				pcur->before = pbefore;
				
				BLOCK* pnext = pnode->next;
				
				pcur->next = pnext;

				if (pnext != NULL)
				{
					if (pnext->before != NULL)
					{
						pnext->before = pcur;
					}
				}
				
				free(pnode->memaddr);
				
				free(pnode);

				/*if (m_mempool[m_poolinfo._size_num]->blocknum == 2)
				{
					test_fun(m_poolinfo._size_num);
				}*/	

				return pcur;			
				
			}
			pnode = pnode->next;
		}		
		
		strcpy(errmsg, "mempool exception:max buff has been bigger than _maxnum_inprocess.");
			
		return NULL;
		
	}
	
}
BLOCK* mempool::get_normalnode(int size)
{
	int searchflag = 0;
	//遍历mem pool 得到合适的大小,当为free=0 return NULL
	for (int i=0; i<m_poolinfo._size_num; i++)
	{
		if (m_mempool[i]->blocksize>=size)
		{
			if (m_mempool[i]->free != 0)
			{
				m_mempool[i]->free--;
				
				BLOCK* pnode = m_mempool[i]->block_addr;
				
				while (pnode)
				{					
					if (pnode->flag == UNUSE_BLOCK)
					{
						pnode->flag = USE_BLOCK;
						
						return pnode;
					}
					pnode = pnode->next;
				}
			}
			else
			{
				strcpy(errmsg, "mempool exception:no unuse_block in mempool.");
				 
				return NULL;
			}
		}
	}		
}


void mempool::putmemnode(BLOCK* pblock)
{
	pblock->flag = UNUSE_BLOCK;

	if (pblock->size > m_poolinfo._max_buf)
	{
		m_mempool[m_poolinfo._size_num]->free++;
	
		return;
	}
	
	for (int i=0; i<m_poolinfo._size_num; i++)
	{
		if (m_mempool[i]->blocksize>=pblock->size)
		{
			m_mempool[i]->free++;

			break;
		}
	}
}

long mempool::mempooltotalsize(MEMINFO& poolinfo)
{

	if (poolinfo._size_num >= (DIFF_SIZENUM-1))
	{
		strcpy(errmsg, "mempool exception:mem pool diff size bigger than DIFF_SIZENUM.");

		return 0;
	}
	m_poolinfo = poolinfo;
	
	m_poolinfo._totalsize = 0;

	for (int i=0; i<m_poolinfo._size_num; i++)
	{
		m_poolinfo._totalsize += (m_poolinfo._mem_size[i][0]*m_poolinfo._mem_size[i][1]);
	}
	m_poolinfo._max_buf = m_poolinfo._mem_size[m_poolinfo._size_num-1][0];

	return m_poolinfo._totalsize;
}

bool mempool::create_mempool()
{
	bool bret = true;
	
	if (m_poolinfo._totalsize != 0)
	{
		ptmpaddr = (void*)malloc(m_poolinfo._totalsize);

		if (ptmpaddr != NULL)
		{

			for (int i=0; i<m_poolinfo._size_num; i++)
			{
				m_mempool[i] = (MEMPOOL*)malloc(sizeof(MEMPOOL));

				m_mempool[i]->blocksize = m_poolinfo._mem_size[i][0];
				
				m_mempool[i]->blocknum = m_poolinfo._mem_size[i][1];

				m_mempool[i]->free = m_mempool[i]->blocknum;

				m_mempool[i]->block_addr = create_blocklist(m_mempool[i]->blocksize, m_mempool[i]->blocknum, ptmpaddr);

				ptmpaddr += m_mempool[i]->blocksize * m_mempool[i]->blocknum;
			}
			//初始化超过范围的list,并将其挂载个数设置为0
			m_mempool[m_poolinfo._size_num] = (MEMPOOL*)malloc(sizeof(MEMPOOL));
			
			m_mempool[m_poolinfo._size_num]->blocknum = 0;

			m_mempool[m_poolinfo._size_num]->block_addr = NULL;
		}
		else			
		{
			bret = false;
			snprintf(errmsg, 255, "mempool exception: malloc mem size %d error.", m_poolinfo._totalsize);
		}
	}
	else
	{
		bret = false;
		strcpy(errmsg, "mempool exception: mem pool size = 0.");
	}
	return bret;
}


BLOCK* mempool::create_blocklist(int blocksize, int blocknum, void* memaddr)
{	
	BLOCK* phead = NULL;
	BLOCK* pcur = NULL;
	BLOCK* pbefore = NULL;
	BLOCK* pnext = NULL;
	phead = (BLOCK*)malloc(sizeof(BLOCK));

	pcur = phead;
	pcur->before = NULL;	
	pcur->next = NULL;
	
	for (int i=0; i<blocknum; i++)
	{
		pcur->size = blocksize;

		pcur->flag = UNUSE_BLOCK;
		
		if (memaddr != NULL)
		{
			pcur->memaddr = memaddr;
		}
		else
		{
			strcpy(errmsg, "mempool exception:create_blocklist error");
		
			break;
		}
		memaddr += blocksize;
		
		pcur->before = pbefore;

		if (i < (blocknum-1))
		{
			pnext = (BLOCK*)malloc(sizeof(BLOCK));

			pnext->before = pcur;

			pcur->next = pnext;			

			pbefore = pcur;

			pcur = pnext;
		}
		else
		{
			pcur->next = NULL;
			
			pcur->before = pbefore;
		}
	}
	return phead;
}

3、支持多线程的无锁同步方式

 
<span style="white-space:pre">	</span><pre name="code" class="cpp">#ifndef __NOLOCKMODE_H
#define __NOLOCKMODE_H

/**********************************************************************
*Author:zp		Date:14-8-22
************************************************************************/

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

class scalock
{
public:

	scalock()
	{
		m_mutex = 0;
		m_lock = 1;
		m_unlock = 0;
	}
	
	~scalock(){}

	void sca_lock();

	void sca_unlock();

	bool sca_trylock();	
	
private:

	int m_mutex;

	int m_lock;

	int m_unlock;
};

inline void scalock::sca_lock()
{
	while (!(__sync_bool_compare_and_swap(&m_mutex, m_unlock, m_lock)))
	{		
		usleep(10);
	}
}

inline bool scalock::sca_trylock()
{
	int count = 0;

	while (count < 5)
	{
		if (__sync_bool_compare_and_swap(&m_mutex, m_unlock, m_lock))	//if true 

			return true;

		count++;

		usleep(10);
	}
	return false;
}

inline void scalock::sca_unlock()
{	
	__sync_bool_compare_and_swap(&m_mutex, m_lock, m_unlock);
}

#endif

<span style="white-space:pre">	</span>4、main函数测试
<span style="white-space:pre">		</span>在线程和多线线程中测试通过。运行正常。
<pre name="code" class="cpp">#include <iostream>
#include "mempool.h"
#include <pthread.h>
#include <unistd.h>

bool check_fun(BLOCK* block)
{
	bool bret = true;
	
	if (block == NULL)
	{
		bret = false;
		
		std::cout<<mempool::getinstance()->getlasterror()<<std::endl;
	}
	else
	{
		std::cout<<"block size:"<<block->size<<std::endl;
	}
	return bret;
}

void* thread_run(void* arg)
{
	int num = 0;
	int size = 10;
	while (num<100)
	{
		BLOCK* pblock = mempool::getinstance()->getmemnode(size);

		if (pblock == NULL)
		{
			 std::cout<<mempool::getinstance()->getlasterror()<<std::endl;
		}
		else
		{
			snprintf((char*)pblock->memaddr, pblock->size, "test data- num:%d size:%d.", num, size);
			
			std::cout<<"threadid:"<<pthread_self()<<" "<<(char*)pblock->memaddr<<std::endl;

			mempool::getinstance()->putmemnode(pblock);	
		}
		num++;
		
		size = size+10;
		
		usleep(10*1000);
	}
}

int main(void)
{
	MEMINFO _loopstate;
	
	_loopstate._size_num = 3;
	_loopstate._mem_size[0][0] = 70;
	_loopstate._mem_size[0][1] = 100;
	_loopstate._mem_size[1][0] = 100;
	_loopstate._mem_size[1][1] = 100;
	_loopstate._mem_size[2][0] = 200;
	_loopstate._mem_size[2][1] = 100;	
	_loopstate._maxnum_inprocess = 2;	
	mempool::init(_loopstate);
	
	std::cout<<"mem pool size:"<<mempool::getinstance()->get_totalbyte()<<std::endl;

	mempool::getinstance()->test_fun(-1);

//单线程测试实例	
	BLOCK* tmp1 = mempool::getinstance()->getmemnode(20);
	BLOCK* tmp2 = mempool::getinstance()->getmemnode(20);
	BLOCK* tmp3 = mempool::getinstance()->getmemnode(100);
	BLOCK* tmp4 = mempool::getinstance()->getmemnode(100);
		

	check_fun(tmp1);
	check_fun(tmp2);
	check_fun(tmp3);
	check_fun(tmp4);
	
	char*val1 = (char*)tmp1->memaddr;
	char*val2 = (char*)tmp2->memaddr;
	char*val3 = (char*)tmp3->memaddr;
	char*val4 = (char*)tmp4->memaddr;
	

	char testchar_1[] = "0123456789012345678";
	char testchar_2[] = "9876543210987654321";
	
	memcpy(val1, testchar_1, strlen(testchar_1));
	memcpy(val2, testchar_2, strlen(testchar_2));
	memcpy(val3, testchar_1, strlen(testchar_1));
	memcpy(val4, testchar_2, strlen(testchar_2));

	
	

	std::cout<<"val1:"<<val1<<std::endl;
	std::cout<<"val2:"<<val2<<std::endl;
	std::cout<<"val3:"<<val3<<std::endl;
	std::cout<<"val4:"<<val4<<std::endl;

//多线程测试

	int threadnum = 10;
	pthread_t thrdid[64];

	for (int i=0; i<threadnum; i++)
	{
		pthread_create(&thrdid[i], NULL, thread_run, NULL);
	}
	for (int i=0; i<threadnum; i++)
	{
		pthread_join(thrdid[i], NULL);
	}

	mempool::getinstance()->mem_destroy();
	
	return 0;
}


 
 



 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值