常用内存块及内存池实现2(C++)

本文介绍了一种通用内存池实现方式,支持追加缓存但不适用于不同类型对象混合使用。通过示例展示了如何创建内存池、分配和释放内存,并提供了关键代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/*
* @note		:通用内存块及内存池实现
* @author	:Andy.Ro
* @email	:Qwuloo@qq.com
*
* --------------------------------------------------------------------------------
* @mark		:
*			优点:支持追加缓存
*			缺点:
*				1.不支持不同类型结构或类对象共存在一个池上
*				2.由于是字节分配,无法调用构造函数及运行时类型信息(dynamic_cast<TYPE>失效)检查,不支持对象虚函数调用
* --------------------------------------------------------------------------------
*
* @example.1: 含追加缓存
*	xBuffer<io_t>  g_pool(5,1024);
*	p_node_t <io_t>* t = g_pool.alloc();
*	t->data.buf = t->get_offset();
*	t->data.len = g_pool.get_offset_size();
*	g_pool.free(t);
*	g_pool.clear();
* @example.2: 无追加缓存
*	xBuffer<xClient> g_pool(20,0);
*	p_node_t<xClient>* t = g_pool.alloc();
*	g_pool.free(t);
*	g_pool.clear();
*/
#ifndef _XBUFFER_P_H_INCLUDE_
#define _XBUFFER_P_H_INCLUDE_

#include "../xThread/xThread.h"

//------------------------------------------------------------------------
// p_node_t<TYPE> 节点
//------------------------------------------------------------------------
class p_node_t
{
public:
	// @note: 返回节点数据部分
	inline char* get_data(void)
	{
		return (char *)(this + 1);
//		return (char *)((char *)this + sizeof(p_node_t));
	}
public:
	// 结构分布如下:
	// -------------------------
	// 指针结构 | 数据长度 | 追加缓存
	// -------------------------
	p_node_t * prev,*next;
	u32_t             len; // 数据长度
};

class ESMT::xMutex;
class ESMT::xEvent;

//------------------------------------------------------------------------
// block_p_node_t 单(一)个内存块,由N个节点(sizeof(p_node_t<TYPE>) + offset)构成
//------------------------------------------------------------------------
class block_p_node_t
{
public:
	// @note: 返回块数据部分
	inline p_node_t* get_data(void)
	{
		return (p_node_t *)((char *)this + sizeof(block_p_node_t));
	}

	// @note: 申请单(一)个内存块
	// @param header <block_p_node_t*&> : 块头
	// @param tail   <block_p_node_t*&> : 块尾
	// @param offset <u32_t>		  : 追加缓存大小 sizeof(p_node_t<TYPE>) + offset
	// @param N      <u32_t>          : 块所包含的节点(sizeof(p_node_t<TYPE>) + offset)数
	static block_p_node_t * create(block_p_node_t*& header, block_p_node_t*& tail, u32_t offset, u32_t N)
	{
		//
		/// sizeof(block_p_node_t) + (sizeof(p_node_t<TYPE>) + offset) * N
		//
		block_p_node_t * block = (block_p_node_t *)new char[
				 sizeof(block_p_node_t) +
				(sizeof(p_node_t      ) + offset) * N];
		if ( ! block )
		{
			fprintf(stderr,"alloc/new failed,memery overflow.\n");
			return NULL;
		}
		block->prev = NULL;
		block->next = header;

		if( header )
		{
			header->prev = block;
			header = header->prev;
		}
		else tail = header = block;

		return block;
	}

	// @note: 清理内存块
	void clear(void)
	{
		block_p_node_t * block = this;

		while( block )
		{
			char * pbytes = (char *)block;
			block = block->next;
			delete [] pbytes;
		}
	}
public:
	block_p_node_t * prev,*next;
};

//------------------------------------------------------------------------
// xBuffer_p 内存池
//------------------------------------------------------------------------
class xBuffer_p
{
public:
	// @param blocksize <u32_t> : 单个内存块中所包含的节点(p_node_t<TYPE>)数,每次申请一个内存块
	// @param offset    <u32_t> : 追加缓存大小 sizeof(p_node_t<TYPE>) + offset
	xBuffer_p(u32_t blocksize = 20,u32_t offset = 0);

	// @note: 从池中申请内存
	inline p_node_t * alloc(void)
	{
		return this->_create(NULL,NULL);
	}
	
	// @note: 入队:数据来了,写入数据
	// @param data <TYPE const*> : 数据
	// @param buf  <char const*> : 追加数据(接口预留)
	// @param len  <u32_t>       : 追加数据大小(接口预留)
	p_node_t * enqueue(char const* buf = NULL, u32_t len = 0)
	{
		p_node_t * node = NULL;
		
		// 头部写入,尾部读出
		this->_head_node_mutex.enter();
		if ( node = this->_create(NULL,this->_head_node) )
		{
			// 实际所含数据长度
			node->len = len;
			// 拷贝追加缓存数据
			memcpy_s(node->get_data(), this->_offset_size, (void const*)buf, len);
			if( this->_head_node ) {
				_head_node->prev = node;
				this->_head_node = _head_node->prev;
			}
			else {
				this->_tail_node = this-> _head_node = node;
				// 队列非空
				__nonsignaled(this->_empty_event);
			}

			// 有数据可读
			__signaled(this->_readable_event);
		}
		this->_head_node_mutex.leave();
		
		return node;
	}
	// @note: 等待数据
	p_node_t * wait_data(void)
	{
		__wait_signal(this->_readable_event,INFINITE);
		return dequeue();
	}
	// @note: 出队:有数据了,读出数据
	p_node_t * dequeue(void)
	{
		p_node_t * node = NULL;
		
		// 头部写入,尾部读出
		this->_tail_node_mutex.enter();
		if ( this->_tail_node )
		{
			// 读的不是头节点
			if ( this->_tail_node != this->_head_node )
			{
				node = this->_tail_node;
				this->_tail_node = this->_tail_node->prev;
				node->prev = node->next = NULL;
			}
			else
			{
				// 读的是头节点,可能正在写数据,等写完再读(因为不能同时读写相同节点)
				__wait_signal(this->_readable_event,INFINITE);
				
				node = this->_tail_node;
//				this->_tail_node = this->_tail_node->prev;
				node->prev = node->next = NULL;
				
				this->_head_node_mutex.enter(); assert( this->_tail_node == this->_head_node );
				
				if ( this->_tail_node == this->_head_node) {
					this->_tail_node = this-> _head_node = NULL;
					// 队列已空
					__signaled(this->_empty_event);
				}
				else {
					this->_tail_node = this->_tail_node->prev; assert( this->_tail_node );
					this->_tail_node->next = NULL;
				}
				
				this->_head_node_mutex.leave();
			}
		}
		this->_tail_node_mutex.leave();

		return node;
	}
	
	// @note:比较两数据包节点序列编号
	// @param pa <p_node_t*>:新数据节点
	// @param pb <p_node_t*>:待比较节点
	typedef int (*compare_func_ptr) (p_node_t * pa, p_node_t * pb);
	// @note: 根据比较规则添加到有序队列
	void orderinsert(compare_func_ptr compare_ptr, char const* buf, u32_t len)
	{
		p_node_t * pre = NULL,*cur = _head_node,*ptr;
		
		// ptr节点为新数据节点,cur节点为遍历节点
		if ( ptr = this->_create(NULL,NULL) )
		{
			// 实际所含数据长度
			ptr->len = len;
			// 拷贝追加缓存数据
			memcpy_s(ptr->get_data(), len, (void const*)buf, len);

			while ( cur )
			{
				// 执行比较规则
				if( (*compare_ptr)(ptr, cur) > 0 )
				{
					break;
				}
				pre = cur;
				cur = cur->next;
			}
			// 当前节点之前插入
			if ( !pre )
			{
				// 插入头部
				ptr-> next = this->_head_node;
				_head_node = ptr;

				++this->_node_list_size;
			}
			else
			{
				ptr->next = cur;
				pre->next = ptr;
				
				++this->_node_list_size;
			}
		}
	}
	// @note: 
	inline p_node_t * top(void)
	{
		return this->_head_node;
	}
	// note: 弹出队头节点
	inline p_node_t * pop(void)
	{
		p_node_t * node  = this->_head_node;
		this->_head_node = node->next;
		node->next = node->prev = NULL;
		if( this->_head_node )
			this->_head_node->prev = NULL;
		--this->_node_list_size;
		return node;
	}

	// @note: 释放内存到池
	inline void free(p_node_t * node)
	{
// 		bzero(node->get_data(), this->_offset_size);
		bzero(node, sizeof(p_node_t) + this->_offset_size);

		this->_free_list_mutex.enter();
		node->prev = NULL;
		node->next = this->_free_list;
		if( this->_free_list ) _free_list->prev = node;
		this->_free_list = node;
		this->_free_list_mutex.leave();
	}
	
	// @note: 清理内存池
	inline void clear(BOOL linear = FALSE)
	{
		this->_b_clearing = TRUE;
		// 不允许申请节点
		this->_free_list_mutex.enter();
		
		// 不允许入队操作
		this->_head_node_mutex.enter();
		this->_head_node = NULL;
		this->_head_node_mutex.leave();
		
		if ( linear ) __wait_signal(this->_empty_event,INFINITE);
		// 不允许出队操作
		this->_tail_node_mutex.enter();
		this->_tail_node = NULL;
		this->_tail_node_mutex.leave();

		this->_list_mutex.enter();
		SAFE_CLEAR(_head_block);
		_head_block = _tail_block = NULL;
		this->_list_mutex.leave();
		
		_free_list = NULL;
		this->_free_list_mutex.leave();

		this->_b_clearing = FALSE;
	}
	// @note: 返回追加缓存大小
	inline u32_t get_offset_size(void)
	{
		return this->_offset_size;
	}
protected:
	// @param 申请内存块
	p_node_t * _create(p_node_t * prev = NULL, p_node_t * next = NULL);

public:
	
	u32_t _offset_size;			// 追加缓存大小 sizeof(p_node_t<TYPE>) + offset
	u32_t _block_size;			// 单个内存块所包含的节点(sizeof(p_node_t<TYPE>) + offset)数,每次申请一个内存块
	u8_t  _b_clearing;
	
	p_node_t * _head_node;	// 双链表头节点
	p_node_t * _tail_node;	// 双链表尾节点
	u32_t _node_list_size;
	ESMT::xMutex   _head_node_mutex;	// 同步头部写数据队列
	ESMT::xMutex   _tail_node_mutex;	// 同步尾部读数据队列
	
	ESMT::xEvent   _readable_event; // 事件通知并发读
	ESMT::xEvent   _empty_event;	// 数据队列为空

	p_node_t * _free_list;				// 空闲节点链表
	ESMT::xMutex   _free_list_mutex;	// 同步空闲链表
	
	block_p_node_t * _head_block;	// 内存块头
	block_p_node_t * _tail_block;	// 内存块尾
	ESMT::xMutex	 _list_mutex;	// 同步块链表
public:
	inline ~xBuffer_p(void)
	{
		this->clear();
	}
};

inline p_node_t * xBuffer_p::_create(p_node_t * prev, p_node_t * next)
{
	if ( this->_b_clearing ) {
		return NULL;
	}
	this->_free_list_mutex.enter();
	if( !this->_free_list )
	{
		this->_list_mutex.enter();
		block_p_node_t::create(this->_head_block, this->_tail_block, _offset_size, _block_size);
#if 0
		// _offset_size == 0
		p_node_t * node  = (p_node_t *)_head_block->get_data();
		node += ()_block_size - 1;
		
		for(u32_t cnt = this->_block_size; cnt > 0; --cnt, --node)
		{
// 			bzero(node->get_data(), this->_offset_size);
			bzero(node, sizeof(p_node_t) + this->_offset_size);
			node->prev = NULL;
			node->next = this->_free_list;
			_free_list = node;
		}
#else
		// _offset_size >  0
		char * node  = (char *)_head_block->get_data();
		node += (sizeof(p_node_t)+this->_offset_size) * (_block_size - 1);

		for(u32_t cnt = this->_block_size; cnt > 0;
			--cnt, node -= (sizeof(p_node_t)+this->_offset_size))
		{
// 			bzero(((p_node_t *)node)->get_data(), this->_offset_size);
			bzero(node, sizeof(p_node_t) + this->_offset_size);
			
			((p_node_t *)node)->prev = NULL;
			((p_node_t *)node)->next = this->_free_list;
			_free_list = (p_node_t *)node;
		}
#endif
		this->_list_mutex.leave();
	}
	
	p_node_t * node = this->_free_list;
	_free_list = this->_free_list->next;
	node->prev = prev;
	node->next = next;
	this->_free_list_mutex.leave();
	return node;
}

#endif // _XBUFFER_P_H_INCLUDE_
#include "../Interface/xTypes.h"
#include "xBuffer_p.h"

xBuffer_p::xBuffer_p(u32_t blocksize /* = 20 */,u32_t offset /* = 0 */)
	:_readable_event(FALSE,FALSE),_empty_event(FALSE,TRUE)
{
	_b_clearing = FALSE;
	_node_list_size = 0;
	_head_node = _tail_node = NULL;
	_free_list   = NULL;
	_block_size  = blocksize;
	_offset_size = offset;
	_head_block = _tail_block = NULL;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值