多线程下快速对象池,可以尽量避免用锁

来源:互联网 发布:audio js控制 编辑:程序博客网 时间:2024/06/16 02:17

在服务器端内存管理是一个十分重要的事情,特别是在多线程下.

    下面是一个完整的对象池,在多线程中依然可以保持高速的内存分配和回收.

    其中vector和list都用了stl的.这个可以重新写下.

 

在多线程中,需要设置下SetThreadSefeParams,设置锁 和 设置EAA操作为原子操作

 

------------lock.h


#pragma once


class ILock
{
public:
 virtual ~ILock( void )
 {

 }

 virtual bool Lock( void )  = 0;
 virtual void UnLock( void )= 0;
};

class NULL_LOCK : public ILock
{
public:
 virtual bool Lock( void )
 {
  return true;
 }

 virtual void UnLock( void )
 {
 }
};

class CLockGuard
{
public:
 CLockGuard( ILock* lock ) : m_lock( lock )
 {
  m_lock->Lock( );
 }

 ~CLockGuard( void )
 {
  m_lock->UnLock( );
 }

private:
 ILock* m_lock;
};

//#define CLockGuard(x) err_avoke

 

------------trunk.h


#pragma once

#include <assert.h>
#include <vector>
#include <list>
#include <map>
using namespace std;


class CChunk
{
public:
 CChunk( void ) : m_trunk( 0 )
 {

 }
 ~CChunk( void )
 {

 }

 void allocate_resize( unsigned int chunksize, size_t datasize )
 {
  m_trunk = ::malloc( datasize*chunksize );
  assert( m_trunk );
  char* p = (char*)m_trunk;
  for ( unsigned int i=0; i<chunksize; ++i )
  {
   m_datas.push_back( p );
   p += datasize;
  }
 }

 void resize( unsigned int chunksize )
 {
  m_datas.resize( chunksize );
 }

 void free( void )
 {
  if ( m_trunk )
  {
   ::free( m_trunk );
   m_trunk = 0;
  }
 }

public:
 void*   m_trunk;
 vector<void*> m_datas;
};

 

 

----------trunkmanager.h


#pragma once


#include "trunk.h"


typedef int (*exchange_and_add)( int volatile*, int );


class CChunkManager
{
public:
 CChunkManager( void )
  : m_chunksize( 0 ), m_datasize( 0 )
  , m_usedchunk_pos( 0 ), m_freechunk_count( 0 ), m_eaa_fun( 0 )
 {
  
 }

 ~CChunkManager( void )
 {

 }

 bool init( unsigned int chunksize, size_t datasize, exchange_and_add fun )
 {
  m_chunksize  = chunksize;
  m_datasize  = datasize;

  m_used_chunk.allocate_resize( m_chunksize, m_datasize+sizeof(CChunkManager*)+sizeof(int) );
  for ( unsigned int i=0; i<m_chunksize; ++i )
  {
   void* p  = m_used_chunk.m_datas[i];
   set_chunk_data( (char*)p, datasize, this, i );
  }

  m_free_chunk.resize( m_chunksize );
  m_usedchunk_pos  = 0;
  m_freechunk_count = 0;
  m_eaa_fun   = fun;

  return true;
 }

 void fini( void )
 {
  m_used_chunk.free( );
  m_free_chunk.free( );
 }

 // 返回是否已经用完
 bool allocate( void*& data_ptr )
 {
  int now_usedchunk_pos = (*m_eaa_fun)( &m_usedchunk_pos, 1 );

  //if ( now_usedchunk_pos>=m_chunksize ) return true;

  data_ptr = m_used_chunk.m_datas[now_usedchunk_pos];

  return (unsigned int)now_usedchunk_pos>=(m_chunksize-1);
 }

 // 返回是否可以reset
 bool free( void* data_ptr )
 {
  int pos = get_chunk_pos( (char*)data_ptr, m_datasize );
  m_free_chunk.m_datas[pos] = data_ptr;

  int now_freechunk_count = (*m_eaa_fun)( &m_freechunk_count, 1 );

  return (unsigned int)now_freechunk_count>=(m_chunksize-1);
 }

 void reset( void )
 {
  m_usedchunk_pos  = 0;
  m_freechunk_count = 0;
 }
 
 static void set_chunk_data( char* p, size_t datasize, CChunkManager* pcm, int pos )
 {
  p   +=datasize;
  CChunkManager** ppcm = (CChunkManager**)( p );
  *ppcm  = pcm;

  p   += sizeof(CChunkManager*);
  int*  ppos= (int*)( p );
  *ppos  = pos;
 }

 static CChunkManager* get_chunk_manager( char* p, size_t datasize )
 {
  p +=datasize;
  CChunkManager** ppcm = (CChunkManager**)( p );

  return *ppcm;
 }

 static int get_chunk_pos( char* p, size_t datasize )
 {
  p +=(datasize+sizeof(CChunkManager*));
  int* ppos= (int*)( p );

  return *ppos;
 }

private:
 unsigned int m_chunksize;
 size_t   m_datasize;

 CChunk   m_used_chunk;
 volatile int m_usedchunk_pos;

 CChunk   m_free_chunk;
 volatile int m_freechunk_count;

 exchange_and_add m_eaa_fun;
};

 

 

----------objectpool.h


#pragma once

#include "trunkmanager.h"
#include "lock.h"

#ifdef _MSC_VER
#define THREAD_LOCAL_STORAGE __declspec(thread)
#else
#define THREAD_LOCAL_STORAGE __thread
#endif // _MSC_VER

inline
static ILock* DefaultLock( void )
{
 static NULL_LOCK nulllock;
 return &nulllock;
}

inline
static int Default_EAA( int volatile* value, int addvalue )
{
 int nowvalue = *value;
 *value += addvalue;
 return nowvalue;
}

template<class T, int CHUNKSIZE=32>
class CObjectPool
{
public:
 CObjectPool( void )
 {
 }

 ~CObjectPool( void )
 {
 }

 static void SetThreadSefeParams( ILock* lock, exchange_and_add eaa_fun )
 {
  m_lock  = lock;
  m_eaa_fun = eaa_fun;
 }

 static void DestoryPool( )
 {
  CLockGuard l( m_lock );

  for ( list<CChunkManager*>::iterator it=m_alls.begin(); it!=m_alls.end(); ++it )
  {
   (*it)->fini();
   delete *it;
  }

  m_frees.clear();
  m_alls.clear();
 }

 static void* operator new(size_t alloclength)
 {
  assert( sizeof(T)==alloclength );
  return Alloc_From_Pool( );
 }

 static void operator delete(void* deletepointer)
 {
  Free_To_Pool( deletepointer );
 }

private:
 static void* Alloc_From_Pool( void )
 {
  CChunkManager* cm = GetCurrentChunkManger( );

  void* p = 0;
  if ( cm->allocate( p ) )
  {
   ResetCurrentChunkManager( );
  }

  return p;
 }

 static void Free_To_Pool( void* deletepointer )
 {
  if ( deletepointer )
  {
   CChunkManager* pcm = CChunkManager::get_chunk_manager( (char*)deletepointer, sizeof(T) );
   if ( pcm && pcm->free( deletepointer ) )
   {
    pcm->reset( );

    Push_ChunkManger( pcm );
   }
  }
 }

 static CChunkManager* GetCurrentChunkManger( void )
 {
  if ( m_current==0 )
  {
   m_current = Pop_ChunkManger( );
  }

  return m_current;
 }

 static void ResetCurrentChunkManager( void )
 {
  m_current = Pop_ChunkManger( );
 }

 static CChunkManager* Pop_ChunkManger( void )
 {
  CChunkManager* cm = 0;

  {
   CLockGuard l( m_lock );

   if ( !m_frees.empty() )
   {
    cm = m_frees.front();
    m_frees.pop_front();
   }
  }

  if ( 0==cm )
  {
   cm = new CChunkManager( );
   cm->init( CHUNKSIZE, sizeof(T), m_eaa_fun );

   {
    CLockGuard l( m_lock );
    m_alls.push_back( cm );
   }
  }

  return cm;
 }

 static void Push_ChunkManger( CChunkManager* cm )
 {
  CLockGuard l( m_lock );
  m_frees.push_back( cm );
 }

private:
 static THREAD_LOCAL_STORAGE CChunkManager* m_current;
 static ILock*        m_lock;
 static exchange_and_add      m_eaa_fun;
 static list<CChunkManager*>     m_frees;
 static list<CChunkManager*>     m_alls;
};

template<class T, int CHUNKSIZE>
THREAD_LOCAL_STORAGE CChunkManager* CObjectPool<T, CHUNKSIZE>::m_current = 0;

template<class T, int CHUNKSIZE>
ILock* CObjectPool<T, CHUNKSIZE>::m_lock = DefaultLock( );

template<class T, int CHUNKSIZE>
exchange_and_add CObjectPool<T, CHUNKSIZE>::m_eaa_fun = Default_EAA;

template<class T, int CHUNKSIZE>
list<CChunkManager*> CObjectPool<T, CHUNKSIZE>::m_frees;

template<class T, int CHUNKSIZE>
list<CChunkManager*> CObjectPool<T, CHUNKSIZE>::m_alls;

 

 

------------例子objectpool.cpp

// objectpool.cpp : 定义控制台应用程序的入口点。
//

#include <iostream>
#include "source/objectpool.h"


class CTest : public CObjectPool<CTest>
{
public:
 CTest( void )
 {
  cout<<"CTest"<<endl;
 }
 ~CTest( void )
 {
  cout<<"~CTest"<<endl;
 }

 int m_test;
};


int main(int argc, char** argv)
{
 //CTest::SetThreadSefeParams(  );

 CTest* t0 = new CTest( );
 CTest* t1 = new CTest( );
 CTest* t2 = new CTest( );
 
 delete ( t0 );
 delete ( t1 );
 delete ( t2 );

 t0 = new CTest( );
 t1 = new CTest( );
 t2 = new CTest( );

 delete ( t0 );
 delete ( t1 );
 delete ( t2 );


 CTest::DestoryPool( );

 return 0;
}

 

原创粉丝点击