线程安全的内存池 c++ 尝试(二)

来源:互联网 发布:山东网络春晚2016直播 编辑:程序博客网 时间:2024/06/06 02:23

mem_pool.h

#include "mempool.h"
#include <stdio.h>

//links 数组存储了内存池中所有的 存储内存块的链表;
// 因为该内存池约定内存块的大小共有17 种,分别为:
//16b,32b,64b,128b,256b,512b,1k,2k,4k,8k,16k,32k,64k,
//128k,256k,512k,1m,所以links 数组大小为17,
// 如果申请的内存块的大小超过1m,内存池不另存储,直接申请,
//直接释放;

mlink links[17];

static FILE * loginfo;

//初始化内存池;
void mempool_init()
{
 for(int i=0;i<17;i++)
 {
  //下面的操作是给每一个链表申请一个空闲的内存块,
  //该内存块是无法分配出去的,即每一个链表至少有一个
  //空闲的内存块,该内存块只是为了处理链表的添加和
  //删除时操作的方便,虽然浪费了内存,却换来了效率;
  links[i].count=1;
  links[i].phead=malloc(((unsigned int)1)<<(i+4));
  links[i].ptail=links[i].phead;
  mem_block_info * p=(mem_block_info*)links[i].phead;
  p->size=((unsigned int)1)<<(i+4);

  p->pnext=0;

  MUTEXINIT(&(links[i].head_mutex));
  MUTEXINIT(&(links[i].tail_mutex));
 }

 loginfo=fopen("mempool.txt","w+");
}

//从内存池中申请 大小为 size B 的空间;
void * mempool_malloc(unsigned int size)
{
 //实际向内存池匹配的内存块大小为size+sizeof(mem_block_info);
 unsigned int memblock_size=size+MEMBLOCKINFOSIZE;

 //因为内存块前 MEMBLOCKINFOSIZE 个字节是内存池记录
 //该内存块信息所用的,所以当返回该内存块的指针时,
 //需向后移动MEMBLOCKINFOSIZE 个字节;

 printf("mempool_malloc: memblock_size 1: %d b\n",memblock_size);
 fprintf(loginfo,"mempool_malloc: memblock_size 1: %d b\n",memblock_size);

 //如果memblock_size>1m,直接向系统申请;
 if(memblock_size>1024*1024)
 {
  void * p= malloc(memblock_size);
  ((mem_block_info *)p)->size=memblock_size;
  ((mem_block_info*)p)->pnext=0;

  return (void *)p+MEMBLOCKINFOSIZE;
 }

 //计算与memblock_size 匹配的链表的下标;
 unsigned int count=4;
 while(memblock_size>(((unsigned int)1)<<count))
  count++;

 memblock_size=(((unsigned int)1)<<count);

 printf("mempool_malloc: memblock_size 2: %f k\n",(memblock_size)/((double)1024.0));
 fprintf(loginfo,"mempool_malloc: memblock_size 2: %f k\n",(memblock_size)/((double)1024.0));

 int index=count-4;
 int flag;
 void * ret;

 //检查该链表是否有空闲的内存块;
 MUTEXLOCK(&(links[index].head_mutex));

 //该链表没有空闲的内存块
 if(links[index].phead==links[index].ptail)
 {
  flag=EMPTY;

  void * p=malloc(memblock_size);

  if(p==0)
   ret=0;
  else
  {
   ((mem_block_info *)p)->size=memblock_size;
   ((mem_block_info  *)p)->pnext=0;

   ret=(void *)p+MEMBLOCKINFOSIZE;

   links[index].count++;
  }

  MUTEXUNLOCK(&(links[index].head_mutex));
 }
 else//该链表有空闲的内存块;
 {
  flag=NOTEMPTY;
  void * p=links[index].phead;
  links[index].phead=((mem_block_info *)p)->pnext;

  ret=p+MEMBLOCKINFOSIZE;

  MUTEXUNLOCK(&(links[index].head_mutex));
 }

 /*if(flag==EMPTY)
 {
  void * p=malloc(memblock_size);
  ((mem_block_info *)p)->size=memblock_size;
  ((mem_block_info  *)p)->pnext=0;

  ret=p+MEMBLOCKINFOSIZE;
 }*/

 return ret;
}

//向内存池释放内存空间;
void mempool_free(void * pointer)
{
 //向前移动指针,获取该内存块的信息
 pointer-=MEMBLOCKINFOSIZE;
 unsigned int size=((mem_block_info *)pointer)->size;

 printf("mempool_free size: %f k\n",(size)/((double)1024.0));
 fprintf(loginfo,"mempool_free size: %f k\n",(size)/((double)1024.0));

 //该内存块的大小大于1m ,直接释放给系统;
 if(size>1024*1024)
 {
  free(pointer);

  return;
 } 

 //计算与该内存块匹配的链表的下标;
 int count=4;
 while(size>((unsigned int)1)<<count)
  count++;

 if(size<((unsigned int)1)<<count)
 {
  printf("mempool_free error : size is not right \n");
  fprintf(loginfo,"mempool_free error : size is not right \n");

  exit(0);
 }

 int index=count-4;

 //将该内存块添加到与之匹配的链表中去;
 MUTEXLOCK(&(links[index].tail_mutex));
 ((mem_block_info *)pointer)->pnext=0;
 ((mem_block_info *)links[index].ptail)->pnext=pointer;
 links[index].ptail=pointer;

 MUTEXUNLOCK(&(links[index].tail_mutex));

 return;
}

//获得内存池的内存块的全部内存空间;
unsigned int getTotalMemory()
{
 unsigned int ret=0;
 for(int i=0;i<17;i++)
 {
  ret+=(((unsigned int)1)<<(i+4))*links[i].count;

  printf("the links[i] i: %d, count: %d \n",i,links[i].count);
  fprintf(loginfo,"the links[i] i: %d, count: %d \n",i,links[i].count);
 }

 printf("******get the total memory**** : %d \n",ret);
 fprintf(loginfo,"******get the total memory**** : %f m\n",ret/(1024*((double)1024)));
 return ret;

}

//销毁内存池;
void mempool_destroy()
{
 for(int i=0;i<17;i++)
 {
  void * pointer=links[i].phead;

  void * tmp;
  while(pointer!=0)
  {
   tmp=pointer;
   pointer=((mem_block_info *)tmp)->pnext;

   free(tmp);

   links[i].count--;
  }

  if(links[i].count>0)
  {
   printf("error! threre is wrong with the memory :%d\n",i);
   fprintf(loginfo,"error! threre is wrong with the memory :%d\n",i);
  }

  MUTEXDESTROY(&(links[i].head_mutex));
  MUTEXDESTROY(&(links[i].tail_mutex));
 }

 return;
}

 

//*************************************************************

下面是一个测试代码:

#include "pthread.h"
#include "mempool.h"
#include <stdlib.h>
#include <time.h>
#include <stdio.h>

THREADFUNCDECL(new_memory,args)
{
 srand(12);
 unsigned int size=rand()%(1000000)+1;

 size=sizeof(double)*20;
 printf("the main test size: %d b\n",size);
 printf("the main test size: %f k\n",size/(double(1024.0)));

 printf("new memory\n");

 void * pointer=mempool_malloc(size);

 for(int i=0;i<20;i++)
  ((double *)pointer)[i]=0.0;

 for(int i=0;i<20;i++)
  printf("data: %f ",*((double *)pointer));

 Sleep(50);

 printf("free memory\n");
 mempool_free(pointer);
}


int main()
{
 srand(time(0));

 mempool_init();

 THREAD thread;
 THREADID id;

 for(int i=0;i<100;i++)
 {
  THREADCREATE(new_memory,NULL,thread,id);

  printf("the total memory size is : %f m\n",getTotalMemory()/(double(1024*1024)));

  Sleep(0);

 } 

 

 Sleep(10000);

 mempool_destroy();

 return 0;
}

 

/**********************************************************************

因为内存块的申请和释放的复杂度都是O(1),并且在多线程的环境下,这两个操作可以互不干扰,提高了程序的并发性,效率应该不是太差,

虽然这只是一个雏形,不过也是一个不错的尝试了。

原创粉丝点击