1. 程式人生 > >固定尺寸內存塊的緩沖隊列類及C++實現源代碼

固定尺寸內存塊的緩沖隊列類及C++實現源代碼

type erl rac 缺點 fault ons lin 大內存 new

--------------------------------------------------------------------------------
標題: 固定尺寸內存塊的緩沖隊列類及實現源代碼
作者: 葉飛虎
日期: 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);
   }
}

}

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

固定尺寸內存塊的緩沖隊列類及C++實現源代碼