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


    --------------------------------------------------------------------------------
    标题: 固定尺寸内存块的缓冲队列类及实现源代码
    作者: 叶飞虎
    日期: 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: AMaxCount
       long           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;
       else
          FBlockSize  = 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)
       {
          // 取第一项, 而且计数加 1
          result = 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 变成 1
          if (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);
       }
    }
    
    }
    

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

  • 相关阅读:
    python 换行符的识别问题,Unix 和Windows 中是不一样的
    MaxCompute小文件问题优化方案
    MaxCompute小文件问题优化方案
    C++ 中的sort()排序函数用法
    C++ 中的sort()排序函数用法
    简单记录几个有用的sql查询
    bzoj1084(SCOI2005)最大子矩阵
    bzoj1025(SCOI2009)游戏——唯一分解的思路与应用
    bzoj1087互不侵犯King(状压)
    bzoj2748(HAOI2018)音量调节
  • 原文地址:https://www.cnblogs.com/claireyuancy/p/7351345.html
Copyright © 2020-2023  润新知