<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;
}