多线程下快速对象池,可以尽量避免用锁
来源:互联网 发布:audio js控制 编辑:程序博客网 时间:2024/06/16 08:34
在服务器端内存管理是一个十分重要的事情,特别是在多线程下.
下面是一个完整的对象池,在多线程中依然可以保持高速的内存分配和回收.
其中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;
}
- 多线程下快速对象池,可以尽量避免用锁
- 如果可以需尽量避免人口出游高峰期出游
- Delphi多线程 尽量避免使用API创建线程
- 尽量避免多进程多线程混用,当下死锁
- 尽量避免官司缠身
- 互斥对象 可以避免脏读
- 为了避免乱码应尽量少用GB2312编码
- 关于Sql中尽量避免用的查询语句(in....
- 为什么尽量避免使用触发器
- C++尽量避免使用指针
- 我应该尽量避免不幸
- 尽量避免双Key系统
- ST17H26尽量避免switch语句
- 多线程下避免使用单件模式
- 用 sched_yield 避免多线程冲突
- 可以用视图尽量用视图不要用外键
- 从头认识多线程-2.13 synchronized ()代码块不单可以用this,也可以用其他对象
- 多线程的环境中,尽量采用线程池
- GTK的源码安装
- win32串口编程
- 贪吃蛇代码
- 用c++实现协程,实现分布式
- Java中String与Int怎样相互转换
- 多线程下快速对象池,可以尽量避免用锁
- 写完俄罗斯方块后
- 100本名著浓缩而成的100句话
- 用jquery仿google动态补全简单例子
- 我对MVC的理解
- W3School Online
- 俄罗斯方块代码
- 我对MVC的理解
- 我对MVC的理解