--------------------------------------------------------------------------------
标题: 固定尺寸内存块的缓冲队列类及实现源代码
作者: 叶飞虎
日期: 2014.10.21
--------------------------------------------------------------------------------

在一般的线性操作应用中(如: 接收缓冲区), 可能须要频繁分配和释放内存块, 频繁操
作会给系统带来非常大开销, 怎样降低系统开销? 通过拉大分配和释放之间间距来降低操作的
频度, 从而达到降低系统开销。

拉大分配和释放之间间距的方法有非常多, 能够通过大内存块自己管理, 也能够通过内存
块缓冲队列。

本文着重讲内存块缓冲队列, 涉及队列就会考虑到无锁进出队列, 即进队列和
出队列在二个线程中能够同一时候操作。

无锁队列的实现方法有非常多, 有数组方式的环形无锁队
列, 也有链接方式的无锁队列。

数组方式在队列容量确定时比較适合, 而链接方式更适合于
队列容量可变情况, 适用性更好。

数组方式无锁队列见我的博文 <在一读一写限制下,无锁环形队列怎样实现?>
    链接方式无锁队列见我的博文 <一读一写情况下。无锁队列怎样实现?>

本文讲的缓冲队列为链接方式, 链接方式一般通过预分配一个结点作为接力点来实现无
锁队列, 长处是实现简单, 缺点是浪费一个结点的内存, 当结点内存块尺寸较大时浪费就大
了。怎样不浪费一个结点内存的链接方式无锁队列? 当队列中仅仅有一个结点时, 本缓冲队列
中使用了原子锁进行操作, 这是一种平衡策略, 若读者有更好方法最好还是告之中的一个下!

固定尺寸内存块的缓冲队列类(TKYCache)源代码例如以下:

// =======================================
// Unit   : 固定尺寸的内存块缓冲
// Version: 3.0.0.0 (build 2014.10.21)
// Author : Kyee Ye
// Email  : kyee_ye(at)126.com
// Copyright (C) Kyee workroom
// =======================================#ifndef _KYCache_H_
#define _KYCache_H_#include "KYObject.h"// KYLib 2.0 開始使用 KYLib 命名空间
namespace KYLib
{// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/* TKYCache - 固定尺寸的内存块缓冲类 */// 注:
// 1. 为了多线程存取安全, New 和 Delete 分属二个线程时能够同一时候操作而不须要加锁,
//    但多线程 New 时必须用锁控制, 多线程 Delete 时必须用锁控制!
// 2. 此缓冲类一般应用于线性操作的类中, 以降低频繁分配和释放内存的缓冲使用.class TKYCache
{
private:// 内存块的链接typedef struct{void*       Self;                // 内存块所属对象void*       Next;                // 下一块} TLink, *PLink;public:// 构造函数// 1. ABlockSize  内存块的固定尺寸, 取值范围: [0x40..0x40000000]// 2. AMaxCount   内存块缓冲的最大个数TKYCache(long ABlockSize = 1024, long AMaxCount = 256);virtual ~TKYCache();// 属性long           Count() const        { return FPushCount - FPopCount; }long           MaxCount() const     { return FMaxCount; }   // default: AMaxCountlong           BlockSize() const    { return FBlockSize; }  // default: ABlockSize// 设置内存块缓冲的最大个数void           SetMaxCount(long AMaxCount){ FMaxCount = (AMaxCount >= 0) ? AMaxCount : 0; }// 分配固定尺寸的内存块void*          New(){TLink* pItem = DoNew();return (pItem != NULL) ?

(char*)pItem + sizeof(TLink) : NULL; } // 释放固定尺寸的内存块 void Delete(void* ABlock) { if (ABlock != NULL) { TLink* pItem = (TLink*)((char*)ABlock - sizeof(TLink)); if (pItem->Self == this) DoDelete(pItem); } } private: // 运行分配/释放带链接的内存块 TLink* DoNew(); void DoDelete(TLink* ALink); // 运行清除缓冲队列 void DoClear(TLink* AHead); private: TLink* FHead; // 缓冲的头链接 TLink* FTail; // 缓冲的尾链接 long FFlag; // 缓冲队列标志 long FMaxCount; // 缓冲最大个数 long FBlockSize; // 内存块的尺寸 Longword FPushCount; // 压入缓冲计数 Longword FPopCount; // 弹出缓冲计数 }; } #endif

// =======================================
// Unit   : 固定尺寸的内存块缓冲
// Version: 3.0.0.0 (build 2014.10.21)
// Author : Kyee Ye
// Email  : kyee_ye(at)126.com
// Copyright (C) Kyee workroom
// =======================================#include <malloc.h>
#include "KYCache.h"// KYLib 2.0 開始使用 KYLib 命名空间
namespace KYLib
{// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/* TKYCache - 固定尺寸的内存块缓冲类 */// ---------------- 构造函数和析构函数 ----------------
// 构造函数
TKYCache::TKYCache(long ABlockSize, long AMaxCount)
{// 初始化FHead       = NULL;FTail       = NULL;FFlag       = 0;FPushCount  = 0;FPopCount   = 0;// 设置缓冲最大个数FMaxCount   = (AMaxCount >= 0) ? AMaxCount : 0;// 设置内存块的尺寸if (ABlockSize <= 0x40)FBlockSize  = 0x40;else if (ABlockSize <= 0x40000000)FBlockSize  = ABlockSize;elseFBlockSize  = 0x40000000;
}// 析构函数
TKYCache::~TKYCache()
{// 运行清除缓冲队列if (FPopCount != FPushCount){FPopCount   = FPushCount;DoClear(FHead);}
}// ---------------- 私有函数 ----------------
// 运行分配带链接的内存块
TKYCache::TLink* TKYCache::DoNew()
{// 初始化TLink* result = NULL;// 推断缓冲队列是否为空if (FPopCount == FPushCount)result = (TLink*)malloc(sizeof(TLink) + FBlockSize);else if (FPushCount - FPopCount != 1){// 取第一项, 而且计数加 1result = FHead;FHead  = (TLink*)result->Next;FPopCount++;}else{// 取第一项result = FHead;// 推断是否须要等待, 防止 DoDelete 冲突if (InterlockedIncrement(&FFlag) == 1){FPopCount++;if (FPopCount == FPushCount){FHead  = NULL;FTail  = NULL;}InterlockedDecrement(&FFlag);}else{FPopCount++;InterlockedDecrement(&FFlag);// 循环等待 FPushCount 变化while (FPopCount == FPushCount)Sleep(1);}// 改动缓冲的头链接if (result->Next != NULL)FHead = (TLink*)result->Next;}// 初始化链接项if (result != NULL){result->Self = this;result->Next = NULL;}// 返回结果return result;
}// 运行释放带链接的内存块
void TKYCache::DoDelete(TLink* ALink)
{// 推断是否已满if (FPushCount - FPopCount >= (Longword)FMaxCount)free(ALink);else{// 置空ALink->Next = NULL;// 引用计数加 1, 若不等于 1 则等待 DoNew 变成 1if (InterlockedIncrement(&FFlag) != 1)while (FFlag != 1)Sleep(0);// 推断是否为第一项if (FTail == NULL){FTail       = ALink;FHead       = ALink;}else{FTail->Next = ALink;FTail       = ALink;}// 计数加 1, 且引用计数减 1(注: 顺序不能改, 否则可能会导致DoNew死循环)FPushCount++;InterlockedDecrement(&FFlag);}
}// 运行清除缓冲队列
void TKYCache::DoClear(TLink* AHead)
{// 初始化void* pCurr;// 循环释放while (AHead != NULL){pCurr = AHead;AHead = (TLink*)AHead->Next;// 释放free(pCurr);}
}}

--------------------------------------------------------------------------------

转载于:https://www.cnblogs.com/claireyuancy/p/7351345.html

固定尺寸内存块的缓冲队列类及C++实现源代码相关推荐

  1. 【C 语言】字符串操作 ( strlen 与 sizeof 函数 | 计算 字符串长度 与 内存块大小 )

    文章目录 一.strlen 与 sizeof 函数 二.计算 字符串长度 与 内存块大小 一.strlen 与 sizeof 函数 strlen() 函数的作用是获取字符串大小 , 其原理是 从 内存 ...

  2. 一个小改动,CNN输入固定尺寸图像改为任意尺寸图像

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 本文小白将和大家一起学习如何在不使用计算量很大的滑动窗口的情况下对 ...

  3. Linux内核内存管理(1):内存块 - memblock

    Linux内核内存管理 内存块 - memblock rtoax 2021年3月 在英文原文基础上,针对中文译文增加5.10.13内核源码相关内容. 1. 简介 内存管理是操作系统内核中最复杂的部分之 ...

  4. Java并发编程:4种线程池和缓冲队列BlockingQueue

    一. 线程池简介 1. 线程池的概念: 线程池就是首先创建一些线程,它们的集合称为线程池.使用线程池可以很好地提高性能,线程池在系统启动时即创建大量空闲的线程,程序将一个任务传给线程池,线程池就会启动 ...

  5. [译] 流量控制(TC)五十年:从基于缓冲队列(Queue)到基于时间戳(EDT)的演进...

    译者序 本文组合翻译了 Google 2018 年两篇分享中的技术部分,二者讲地同一件事情,但层次侧重不同: Netdev 2018: Evolving from AFAP: Teaching NIC ...

  6. 打包传输结构体或大内存块

    打包传输结构体或大内存块 http://blog.csdn.net/hejishan/article/details/2287190 作者 郑昀 内容   BSTR的解法 SAFEARRAY的解法 b ...

  7. [C++]打包传输结构体或大内存块的四种办法(完全版)

    打包传输结构体或大内存块 作者 郑昀 内容 BSTR的解法 SAFEARRAY的解法 boost::serialization的解法 IStream流的解法 本文假定您熟悉 SAFEARRAY.C++ ...

  8. Shared pool内存块组成结构及4031错误原因分析

    这篇文章是参考甲骨论老相老师的教学视频所做的学习笔记: http://v.youku.com/v_show/id_XMzkyMDQ4MzUy.html 之前提到Shared pool的作用: Shar ...

  9. android 队列执行动画,Android 重学系列 渲染图层-图元缓冲队列初始化

    前言 经过上一篇文章,对开机启动动画的流程梳理,引出了实际上在开机启动动画中,并没有Activity,而是通过OpenGL es进行渲染,最后通过某种方式,把数据交给Android渲染系统. 本文,先 ...

最新文章

  1. 全球及中国模块化塑料带行业供需调查及产销形势预测报告2021-2027年版
  2. eoLinker-API_Shop_验证码识别与生成类API调用的代码示例合集:六位图片验证码生成、四位图片验证码生成、简单验证码识别等...
  3. tls1.1 tls1.2_Java 8将默认使用传输级别安全性(TLS)1.2
  4. IOS-网络(监听网络状态)
  5. mongodb远程连接windows
  6. eclipse如何运行html文件,eclipse中applet嵌入html文件
  7. [译] Facebook杯2013年编程挑战赛——预选赛题目及答案
  8. js验证银行卡号 luhn校验规则
  9. 小程序素材抓取软件_小程序上新丨2020冬季产品图库更新,海量素材随你用!...
  10. numpy.cumsum()函数
  11. 项目启动时 xml报错:Could not find SQL statement to include with refid 'mbgl.panDuanZbsfkxg'
  12. Sql Server系列:数据表操作
  13. mysql 找表重复数据_mysql 数据表中查找重复记录
  14. 计算机键盘电容传感器,电容式触摸感应按键的实现之硬件篇
  15. 个人网站可以申请微信授权登录吗?
  16. Linux服务器查看Ip地址
  17. 前国际奥委会主席罗格去世,敬生命!这些残奥特写太戳了
  18. abp vnext 通过Claim扩展用户表字段
  19. android xposed软重启,Xposed插件安装更新免重启手机方案
  20. EXCEL中怎样提取部分特定的文本?

热门文章

  1. 引入react文件报错_React Native常见问题(一)
  2. vmx进程已提前退出_如何优雅地停止Java进程
  3. ll文件显示为?????_关于shell编程中的文件测试简单的操作实例
  4. Python数据结构与算法(2.5)——循环链表
  5. matlab对有周期性噪声的图像去噪,数字图像中去除周期性噪声研究.doc
  6. eclipse快捷键_Eclipse快捷键
  7. c语言toupper_在C中使用toupper()–实用指南
  8. 使用Kotlin的Android ProgressBar
  9. java组合与继承始示例_Java 8特性与示例
  10. 函数重载函数的引用算重载吗_了解C ++中的函数重载