NDArrayPool源代码解析以及测试程序

 NDArrayPool源代码:

#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 
#include 

#include 

#include 

#include "asynNDArrayDriver.h"
#include "NDArray.h"

// 在认为一个NDArray对象太大前,它必须比所需的尺寸大多少。
#define THRESHOLD_SIZE_RATIO 1.5

static const char *driverName = "NDArrayPool";

/*
 * eraseNDAttributes是一个控制每次用NDArrayPool->alloc()分配一个新数组时是否调用NDArray::clearAttributes()的全局标记。
 * 默认值是0,表示clearAttributes()不被调用。这种模式是高效的,因为它节省了大量的分配/接触分配,并且当一旦
 * 为一个驱动设置了这些属性并且不变化时,这是可以的。如果驱动属性被删除,如果这个标记为0,分配的数组将仍然有这些旧的属性,
 * 设置这个标记在每次分配一个的NDArray时强制删除属性。
 */
volatile int eraseNDAttributes=0;
// 导出这个变量到EPICS IOC
extern "C" {epicsExportAddress(int, eraseNDAttributes);}

/** NDArrayPool构造器
  * [in] pDriver: 指向创建这个对象的asynNDArrayDriver的指针.
  * [in] maxMemory : 允许这个池使用的最大内存字节量,所有NDArray对象求和,0=无限
  */
NDArrayPool::NDArrayPool(class asynNDArrayDriver *pDriver, size_t maxMemory)
  : numBuffers_(0), maxMemory_(maxMemory), memorySize_(0), pDriver_(pDriver)
// 初始化时,NDArray对象数目为0,使用内存字节数为0,可用内存最大字节数为传入的maxMemory
{
  listLock_ = epicsMutexCreate(); // 创建互斥量
}

/** 创建新的NDArray对象。
  * 这个方法应该被管理派生自NDArray类的对象的池对象重写。
  */
NDArray* NDArrayPool::createArray()
{
    return new NDArray;
}

/*
  * 管理派生自NDArray类的对象的池类的hook。
  * 在新的数组已经被分配后,这个hook被调用。
  * [in] pArray: 指向分配的NDArray对象的指针 
  */
void NDArrayPool::onAllocateArray(NDArray *pArray)
{
}

/** 管理派生自NDArray类的对象的池类的hook。
  * 在这个数组已经被保留后,这个hook被调用。
  * [in] pArray : 指向被保留的NDArray对象的指针
  */
void NDArrayPool::onReserveArray(NDArray *pArray)
{
}

/** 管理派生自NDArray类的对象的池类的hook。
  * 在这个数组已经被释放后,这个hook被调用。
  * [in] pArray:指向被释放的NDArray对象的指针 
  */
void NDArrayPool::onReleaseArray(NDArray *pArray)
{
}


/** 分配一个新的NDArray对象,需要前3个参数.
  * [in] ndims:这个NDArray中维度数目.
  * [in] dims :维度的数组,其尺寸必须至少为ndims.
  * [in] dataType : NDArray的数据类型.
  * [in] dataSize :为数组数据分配的字节数目 ; 如果0,则alloc将从ndims, 
  * 如果0,则alloc()将从ndims,dims和dataType计算除所需的尺寸。
  * [in] pData : 指向一个数据缓存的指针;如果NULL,则alloc将分配一个新的数组缓存;如果非0,则认为它指向一个有效缓存。
  * 如果pData不是NULL,则dataSize必须包含已有数组中实际的字节数目,并且这个数组必须足够大来保存这些数组数据。
  * alloc()搜索它的空闲列表来查找一个空闲的NDArray缓存。如果不能找到一个空闲的,则它将分配一个新数组
  * 并且添加它到这个空闲列表。如果分配这个NDArray所需的内存将使得为这个池分配的累积内存超过maxMemory,
  * 则将返回一个错误。alloc()设置返回的NDArray的引用计数为1.
  */
NDArray* NDArrayPool::alloc(int ndims, size_t *dims, NDDataType_t dataType, size_t dataSize, void *pData)
{
  NDArray *pArray=NULL;
  NDArrayInfo_t arrayInfo;
  const char* functionName = "NDArrayPool::alloc:";

  epicsMutexLock(listLock_);

  // 计算所需的NDArray尺寸
  NDArray::computeArrayInfo(ndims, dims, dataType, &arrayInfo); // 根据ndims,dims和dataType获取每个总字节数
  if (dataSize == 0) {
    dataSize = arrayInfo.totalBytes;
  }

  std::multiset::iterator pListElement; // freeListElement对象迭代器
  // 传入的数组数据未空,从空闲列表中获取一个
  if (!pData) {
    //  尝试寻找空闲列表中足够大的数组
    freeListElement testElement(NULL, dataSize);
    pListElement = freeList_.lower_bound(testElement); // dataSize为下限的迭代器,调用一次返回一个freeListElement对象
  } else {// 传入的数组数据不为空,则从空闲列表中获取第一个最小的freeListElement对象
    // dataSize没关系, pData将被替代.
    pListElement = freeList_.begin();
  }

  if (pListElement == freeList_.end()) {
    /* 我们未找到一个足够大的空闲列表,分配一个新数组 */
    numBuffers_++; //NDArray对象数目加1
    pArray = this->createArray();
  } else {
    pArray = pListElement->pArray_; //到一个足够大的空闲列表,取出这个NDArray对象
    if (pData || (pListElement->dataSize_ > (dataSize * THRESHOLD_SIZE_RATIO))) {
      // 我们找到了一个数组,但它太大。设置这个尺寸为0,因而在下面分配它
      memorySize_ -= pArray->dataSize;
      free(pArray->pData);
      pArray->pData = NULL;
    }
    freeList_.erase(pListElement); //空闲列表从删除这个freeListElement对象
  }

  /* 初始化字段:设置这个分配这个NDArray对象的NDArrayPool,引用次数,分配这个NDArray的驱动,数组数据类型,数组数据维度数目 */
  pArray->pNDArrayPool = this;
  pArray->referenceCount = 1;
  pArray->pDriver = pDriver_;
  pArray->dataType = dataType;
  pArray->ndims = ndims;
  // 维度数组置0
  memset(pArray->dims, 0, sizeof(pArray->dims));
  for (int i=0; idims[i].size = dims[i];
    pArray->dims[i].offset = 0;
    pArray->dims[i].binning = 1;
    pArray->dims[i].reverse = 0;
  }

  /* 如果置位了全局标记,删除这些属性 */
  if (eraseNDAttributes) pArray->pAttributeList->clear();

  /* 清除codec */
  pArray->codec.clear();

  /* 到此,pArray存在,但pArray->pData可能是NULL */
  /* 如果调用者传递一个有效缓存,使用那个缓存 */
  if (pData) {
    pArray->pData = pData;
    pArray->dataSize = dataSize;
    memorySize_ += dataSize;
  } else if (pArray->pData == NULL) {
    if ((maxMemory_ > 0) && ((memorySize_ + dataSize) > maxMemory_)) {
      /*
       * 我们没有分配这个数组的足够内存,看我们是否能通过删除数组获取内存
       * 首先删除最大的数组,及从freeList_末尾开始。       
       */
      NDArray *freeArray;
      std::multiset::iterator it;
      // 已用内存+dataSiz大于可用最大内存量,需要释放数组
      while (!freeList_.empty() && ((memorySize_ + dataSize) > maxMemory_)) {
        it = freeList_.end(); // 获取末尾的freeListElement对象
        it--;
        freeArray = it->pArray_;
        // 从空闲列表中删除获取的freeListElement对象
        freeList_.erase(it);
        // 内存使用量减少获取的freeListElement对象的dataSize
        memorySize_ -= freeArray->dataSize;
        // NDArray对象数目减少1
        numBuffers_--;
        // 释放获取的freeListElement对象
        delete freeArray;
      }
    }
    // 如果最大可用内存量有限制并且已用内存量+dataSize大于最大可用内存量
    if ((maxMemory_ > 0) && ((memorySize_ + dataSize) > maxMemory_)) {
      asynPrint(pDriver_->pasynUserSelf, ASYN_TRACE_ERROR,
             "%s: error: reached limit of %ld memory (%d buffers)\n",
             functionName, (long)maxMemory_, numBuffers_);
    } else {
      pArray->pData = malloc(dataSize); // 分配数组数据区
      if (pArray->pData) {//分配成功,设置NDArray的dataSize和
        pArray->dataSize = dataSize; 
        pArray->compressedSize = dataSize;
        memorySize_ += dataSize; // 内存使用量增加dataSize
      }
    }
  }
  // 如果我们没有一个有效内存缓存,设置pArray为NULL来表示错误
  if (pArray && (pArray->pData == NULL)) {
    delete pArray;
    numBuffers_--;
    pArray = NULL;
  }

  // 调用分配hook(用于管理派生自NDArray类的对象的池)
  onAllocateArray(pArray);
  epicsMutexUnlock(listLock_);
  return (pArray);
}

/** 这个方法复制一个NDArray对象。
  * [in] pIn :要被复制的输入数组.
  * [in] pOut:将被复制到的输出数组;可以是NULL或者一个指向一个已有NDArray的指针。
  * [in] copyData:如果这个标记为true,则包括数组数据的所有东西都被复制。如果0, 复制除了数据外(包括属性)的所有东西。
  * [in] copyDimensions :如果这个标记为true, 则即使pOut不为NULL,也复制这些维度;默认为true
  * [in] copyDataType:如果这个标记为true, 即使pOut不为NULL,也复制dataType, 默认为true
  * 返回:返回一个指向输出数组的指针
  *
  * 如果pOut为NULL,首先分配它。如果输出数组对象已经存在(pOut!=NULL),则必须已经分配足够空间给它来保存数据。
  */
NDArray* NDArrayPool::copy(NDArray *pIn, NDArray *pOut, bool copyData, bool copyDimensions, bool copyDataType)
{
  //const char *functionName = "copy";
  size_t dimSizeOut[ND_ARRAY_MAX_DIMS];
  int i;
  size_t numCopy;
  NDArrayInfo arrayInfo;

  /*  如果输出数组不存在,则创建它 */
  if (!pOut) {
    for (i=0; indims; i++) dimSizeOut[i] = pIn->dims[i].size; // 从输入数组的每个维度获取输出数组每个维度尺寸
    pOut = this->alloc(pIn->ndims, dimSizeOut, pIn->dataType, 0, NULL); // 数据类型使用输入数组的数据类型,dataSize取0,则alloc自行计算
    if(NULL==pOut) return NULL;
  }
  // 复制uniqueId, timeStamp,epicsTS 
  pOut->uniqueId = pIn->uniqueId;
  pOut->timeStamp = pIn->timeStamp;
  pOut->epicsTS = pIn->epicsTS;
  // 如果copyDimensions为true,则复制维度数目以及每个维度上的尺寸
  if (copyDimensions) {
    pOut->ndims = pIn->ndims;
    memcpy(pOut->dims, pIn->dims, sizeof(pIn->dims));
  }
  // 如果copyDataType为true,则复制数据类型
  if (copyDataType) {
    pOut->dataType = pIn->dataType;
  }
  // 复制编码算法名
  pOut->codec.name = pIn->codec.name;
  // 复制压缩后的尺寸
  pOut->compressedSize = pIn->compressedSize;
  // 如果copyData为true,
  if (copyData) { // 
    pIn->getInfo(&arrayInfo);
    numCopy = pIn->codec.empty() ? arrayInfo.totalBytes : pIn->compressedSize; // codec.empty()为true,表示没有使用压缩算法
    if (pOut->dataSize < numCopy) numCopy = pOut->dataSize; //需要复制的数据量取数组数据尺寸和输入数组尺寸中的小者
    memcpy(pOut->pData, pIn->pData, numCopy); // 将输入数组中数据区中数据复制到输出数组中数据区
  }
  pOut->pAttributeList->clear(); // 清除输出数组中属性列表中所有属性
  pIn->pAttributeList->copy(pOut->pAttributeList); // 将输入数组中属性列表中所有属性复制到输出数组的属性列表中
  return(pOut);
}

/** 这个方法增加这个NDArray对象的引用次数。
  * [in] pArray :对这个数组增加引用计数.
  * 当一个NDArray被放到一个队列为了之后处理,插件必须调用reserve()。
  */
int NDArrayPool::reserve(NDArray *pArray)
{
  const char *functionName = "reserve";

  /* Make sure we own this array 确认我们拥有这个数组 */
  if (pArray->pNDArrayPool != this) {// 这个NDArray对象不是这个NDArrayPool对象分配的
    asynPrint(pDriver_->pasynUserSelf, ASYN_TRACE_ERROR,
      "%s::%s: ERROR, not owner!  owner=%p, should be this=%p\n",
      driverName, functionName, pArray->pNDArrayPool, this);
    return(ND_ERROR);
  }
  //asynPrint(pDriver_->pasynUserSelf, ASYN_TRACE_FLOW,
  //  "NDArrayPool::reserve pArray=%p, count=%d\n", pArray, pArray->referenceCount);
  epicsMutexLock(listLock_);
  // 如果引用次数少于1,则出问题了,这个NDArray已经被释放了
  if (pArray->referenceCount < 1) {
    cantProceed("%s:reserve ERROR, reference count = %d, should be >= 1, pArray=%p\n",
           driverName, pArray->referenceCount, pArray);
  }
  pArray->referenceCount++; // 传入NDArray对象的引用次数加1

  // 调用保留hook(用于管理派生自NDArray类的对象的池)
  onReserveArray(pArray);
  epicsMutexUnlock(listLock_);
  return ND_SUCCESS;
}

/** 这个方法减小对NDArray对象的引用次数。
  * [in] pArray :对这个数组减少引用次数
  * 当引用次数到达0,NDArray被放回空闲列表。
  * 当一个NDArray被从队列移除并且对其处理结束时,插件必须调用release()。
  * 在调用所有插件后,驱动必须调用release()。
  */
int NDArrayPool::release(NDArray *pArray)
{
  const char *functionName = "release";

  /* 确认我们拥有这个数组 */
  if (pArray->pNDArrayPool != this) {
    asynPrint(pDriver_->pasynUserSelf, ASYN_TRACE_ERROR,
      "%s::%s: ERROR, not owner!  owner=%p, should be this=%p\n",
      driverName, functionName, pArray->pNDArrayPool, this);
    return(ND_ERROR);
  }
  //asynPrint(pDriver_->pasynUserSelf, ASYN_TRACE_FLOW,
  //  "NDArrayPool::release pArray=%p, count=%d\n", pArray, pArray->referenceCount);
  epicsMutexLock(listLock_);
  pArray->referenceCount--;// 引用次数减少1
  if (pArray->referenceCount == 0) {// 引用次数为0
    /* The last user has released this image, add it back to the free list 最后的用户释放这个图像,添加它到空闲列表*/
    freeListElement listElement(pArray, pArray->dataSize);
    freeList_.insert(listElement);
  }
  if (pArray->referenceCount < 0) {
    cantProceed("%s:release ERROR, reference count < 0 pArray=%p\n",
           driverName, pArray);
  }

  // 调用释放释放hook(用于管理派生自NDArray类的池)
  onReleaseArray(pArray);
  epicsMutexUnlock(listLock_);
  return ND_SUCCESS;
}

// 输入数组数据类型和输出数组数据类型之间的转换
template  void convertType(NDArray *pIn, NDArray *pOut)
{
  size_t i;
  dataTypeIn *pDataIn = (dataTypeIn *)pIn->pData; // 输入数组的数据区
  dataTypeOut *pDataOut = (dataTypeOut *)pOut->pData; // 输出数组的数据区
  NDArrayInfo_t arrayInfo;

  pOut->getInfo(&arrayInfo);
  for (i=0; i int convertTypeSwitch (NDArray *pIn, NDArray *pOut)
{
  int status = ND_SUCCESS;

  switch(pIn->dataType) {
    case NDInt8:
      convertType (pIn, pOut);
      break;
    case NDUInt8:
      convertType (pIn, pOut);
      break;
    case NDInt16:
      convertType (pIn, pOut);
      break;
    case NDUInt16:
      convertType (pIn, pOut);
      break;
    case NDInt32:
      convertType (pIn, pOut);
      break;
    case NDUInt32:
      convertType (pIn, pOut);
      break;
    case NDInt64:
      convertType (pIn, pOut);
      break;
    case NDUInt64:
      convertType (pIn, pOut);
      break;
    case NDFloat32:
      convertType (pIn, pOut);
      break;
    case NDFloat64:
      convertType (pIn, pOut);
      break;
    default:
      status = ND_ERROR;
      break;
  }
  return(status);
}

/*
    1、当输入和输出数组都是一维数组时,dim = 0
    1 2 3 4 5 6  => 1 2 3
*/
template  void convertDim(NDArray *pIn, NDArray *pOut,
                                                     void *pDataIn, void *pDataOut, int dim)
{
  dataTypeOut *pDOut = (dataTypeOut *)pDataOut; // 输出数组数据区
  dataTypeIn *pDIn = (dataTypeIn *)pDataIn;     // 输入数组数据区
  /*
    size_t size;   
    size_t offset;                
    int binning;   
    int reverse;
*/ 
  NDDimension_t *pOutDims = pOut->dims; // 输出数组的维度数组
  NDDimension_t *pInDims = pIn->dims;    //输入数组的维度数组
  size_t inStep, outStep, inOffset;
  int inDir;
  int i, bin;
  size_t inc, in, out;

  inStep = 1;
  outStep = 1;
  inDir = 1;
  inOffset = pOutDims[dim].offset;
  for (i=0; i 0) {
        convertDim  (pIn, pOut, pDIn, pDOut, dim-1);
      } else {
        *pDOut += (dataTypeOut)*pDIn;
      }
      pDIn += inc;
    }
    pDOut += outStep;
  }
}

// 
template  int convertDimensionSwitch(NDArray *pIn, NDArray *pOut,
                                                           void *pDataIn, void *pDataOut, int dim)
{
  int status = ND_SUCCESS;

  switch(pIn->dataType) {
    case NDInt8:
      convertDim  (pIn, pOut, pDataIn, pDataOut, dim);
      break;
    case NDUInt8:
      convertDim  (pIn, pOut, pDataIn, pDataOut, dim);
      break;
    case NDInt16:
      convertDim  (pIn, pOut, pDataIn, pDataOut, dim);
      break;
    case NDUInt16:
      convertDim  (pIn, pOut, pDataIn, pDataOut, dim);
      break;
    case NDInt32:
      convertDim  (pIn, pOut, pDataIn, pDataOut, dim);
      break;
    case NDUInt32:
      convertDim  (pIn, pOut, pDataIn, pDataOut, dim);
      break;
    case NDInt64:
      convertDim  (pIn, pOut, pDataIn, pDataOut, dim);
      break;
    case NDUInt64:
      convertDim  (pIn, pOut, pDataIn, pDataOut, dim);
      break;
    case NDFloat32:
      convertDim  (pIn, pOut, pDataIn, pDataOut, dim);
      break;
    case NDFloat64:
      convertDim  (pIn, pOut, pDataIn, pDataOut, dim);
      break;
    default:
      status = ND_ERROR;
      break;
  }
  return(status);
}

static int convertDimension(NDArray *pIn,
                            NDArray *pOut,
                            void *pDataIn,
                            void *pDataOut,
                            int dim)
{
  int status = ND_SUCCESS;
  /* 这个例程被传递:
   * 一个指向输入数据起始位置的指针:
   * 一个指向输出数据起始位置的指针
   * 一个维度的数组
   * 维度索引
   */
  switch(pOut->dataType) {
    case NDInt8:
      convertDimensionSwitch (pIn, pOut, pDataIn, pDataOut, dim);
      break;
    case NDUInt8:
      convertDimensionSwitch  (pIn, pOut, pDataIn, pDataOut, dim);
      break;
    case NDInt16:
      convertDimensionSwitch  (pIn, pOut, pDataIn, pDataOut, dim);
      break;
    case NDUInt16:
      convertDimensionSwitch  (pIn, pOut, pDataIn, pDataOut, dim);
      break;
    case NDInt32:
      convertDimensionSwitch  (pIn, pOut, pDataIn, pDataOut, dim);
      break;
    case NDUInt32:
      convertDimensionSwitch  (pIn, pOut, pDataIn, pDataOut, dim);
      break;
    case NDInt64:
      convertDimensionSwitch  (pIn, pOut, pDataIn, pDataOut, dim);
      break;
    case NDUInt64:
      convertDimensionSwitch  (pIn, pOut, pDataIn, pDataOut, dim);
      break;
    case NDFloat32:
      convertDimensionSwitch  (pIn, pOut, pDataIn, pDataOut, dim);
      break;
    case NDFloat64:
      convertDimensionSwitch  (pIn, pOut, pDataIn, pDataOut, dim);
      break;
    default:
      status = ND_ERROR;
      break;
  }
  return(status);
}

/**  从一个输入NDArray创建一个新的输出NDArray,执行转换操作。
  * 这个函数形式用于仅更改数据类型,不是维度,维度被保留。
  * [in] pIn :输入数组,转换的来源.
  * [out] ppOut : 输出数组,转换结果。
  * [in] dataTypeOut :输出数组的数据类型
  */
int NDArrayPool::convert(NDArray *pIn,
                         NDArray **ppOut,
                         NDDataType_t dataTypeOut)

{
  NDDimension_t dims[ND_ARRAY_MAX_DIMS];
  int i;
  // 输出数组的维度与输入数组的维度一样
  for (i=0; indims; i++) {
    dims[i].size  = pIn->dims[i].size;
    dims[i].offset  = 0;
    dims[i].binning = 1;
    dims[i].reverse = 0;
  }
  return this->convert(pIn, ppOut, dataTypeOut, dims);
}

/** 从一个输入NDArray创建一个新的输出NDArray,执行转换操作。
  * 如果dataTypeout不同于pIn->dataType,转换可以更改数据类型。
  * 它也可以更改维度,outDims其每个维度可以有与输入数组维度(pIn->dims)不同的size,binning,offset和reverse的值。
  * 
  * [in] pIn :这个输入数组,转换的来源.
  * [out]ppOut:输出数组,转换的结果 
  * [in] dataTypeOut:输出数组的数据类型 
  * [in] dimsOut :输出数组的维度.
  */
int NDArrayPool::convert(NDArray *pIn,
                         NDArray **ppOut,
                         NDDataType_t dataTypeOut,
                         NDDimension_t *dimsOut)
{
  int dimsUnchanged;
  size_t dimSizeOut[ND_ARRAY_MAX_DIMS];
  NDDimension_t dimsOutCopy[ND_ARRAY_MAX_DIMS];
  int i;
  NDArray *pOut;
  NDArrayInfo_t arrayInfo;
  NDAttribute *pAttribute;
  int colorMode, colorModeMono = NDColorModeMono;
  const char *functionName = "convert";

  /* 初始化出错 */
  *ppOut = NULL;

  /* 不能转换被压缩的数据 */
  if (!pIn->codec.empty()) {
    fprintf(stderr, "%s:%s: can't convert compressed data [%s]\n",
            driverName, functionName, pIn->codec.name.c_str());
    return ND_ERROR;
  }

  /*  因为我们需要修改它,但我们不要影响调用者,复制输入维度数组 */
  memcpy(dimsOutCopy, dimsOut, pIn->ndims*sizeof(NDDimension_t)); // 维度数由输入数组的维度数决定
  /* 计算输出数组的维度  */
  dimsUnchanged = 1;
  for (i=0; indims; i++) {
    dimsOutCopy[i].size = dimsOutCopy[i].size/dimsOutCopy[i].binning; // 输出数组每个维度的尺寸
    if (dimsOutCopy[i].size <= 0) {
      asynPrint(pDriver_->pasynUserSelf, ASYN_TRACE_ERROR,
        "%s:%s: ERROR, invalid output dimension, size=%d, binning=%d\n",
        driverName, functionName, (int)dimsOut[i].size, dimsOut[i].binning);
      return(ND_ERROR);
    }
    dimSizeOut[i] = dimsOutCopy[i].size; // 存储输出数组每一维度的尺寸的数组
    if ((pIn->dims[i].size  != dimsOutCopy[i].size) || // 只要满足输出数组每个维度上尺寸与输入输入对那个维度不同
      (dimsOutCopy[i].offset != 0) || // 或者输出数组每个维度上有偏移量或者有binning或者反向了,则输出维度就发生了变化
      (dimsOutCopy[i].binning != 1) ||
      (dimsOutCopy[i].reverse != 0)) dimsUnchanged = 0;
  }

  /*  我们知道了输出数组的数据类型和维度,分配它 */
  pOut = alloc(pIn->ndims, dimSizeOut, dataTypeOut, 0, NULL);
  *ppOut = pOut;
  if (!pOut) {
    asynPrint(pDriver_->pasynUserSelf, ASYN_TRACE_ERROR,
      "%s:%s: ERROR, cannot allocate output array\n",
      driverName, functionName);
    return(ND_ERROR);
  }
  /*从输入NDArray对象复制字段到输出NDArray对象  */
  pOut->timeStamp = pIn->timeStamp;
  pOut->epicsTS = pIn->epicsTS;
  pOut->uniqueId = pIn->uniqueId;
  /*  用传递给这个函数的那些维度结构体替换输出NDArray中的dims中存储的维度结构体 */
  memcpy(pOut->dims, dimsOutCopy, pIn->ndims*sizeof(NDDimension_t));
  pIn->pAttributeList->copy(pOut->pAttributeList);

  pOut->getInfo(&arrayInfo);

  if (dimsUnchanged) {
    if (pIn->dataType == pOut->dataType) {
      /*
       * 维度相同并且数据类型相同,则仅复制输入图像到输出图像。
       */
      memcpy(pOut->pData, pIn->pData, arrayInfo.totalBytes);
      return ND_SUCCESS;
    } else {
      /* 我们需要转换数据类型 */
      switch(pOut->dataType) {// 根据输出NDArray中数据类型,将输入NDArray中数据转成输出NDArray中数据类型
        case NDInt8:
          convertTypeSwitch  (pIn, pOut);
          break;
        case NDUInt8:
          convertTypeSwitch  (pIn, pOut);
          break;
        case NDInt16:
          convertTypeSwitch  (pIn, pOut);
          break;
        case NDUInt16:
          convertTypeSwitch  (pIn, pOut);
          break;
        case NDInt32:
          convertTypeSwitch  (pIn, pOut);
          break;
        case NDUInt32:
          convertTypeSwitch  (pIn, pOut);
          break;
        case NDInt64:
          convertTypeSwitch  (pIn, pOut);
          break;
        case NDUInt64:
          convertTypeSwitch  (pIn, pOut);
          break;
        case NDFloat32:
          convertTypeSwitch  (pIn, pOut);
          break;
        case NDFloat64:
          convertTypeSwitch  (pIn, pOut);
          break;
        default:
          //status = ND_ERROR;
          break;
      }
    }
  } else {
    /* 对整个输出NDArray的数据清零 */
    memset(pOut->pData, 0, arrayInfo.totalBytes);
    convertDimension(pIn, pOut, pIn->pData, pOut->pData, pIn->ndims-1);
  }

  /*  设置输出数组中的字段 */
  for (i=0; indims; i++) {
    pOut->dims[i].offset = pIn->dims[i].offset + dimsOutCopy[i].offset;
    pOut->dims[i].binning = pIn->dims[i].binning * dimsOutCopy[i].binning;
    if (pIn->dims[i].reverse) pOut->dims[i].reverse = !pOut->dims[i].reverse;
  }

  /* 
   * 如果帧是RGBx帧,并且我们折叠那个维度,则更改颜色模式
   */
  pAttribute = pOut->pAttributeList->find("ColorMode");
  if (pAttribute && pAttribute->getValue(NDAttrInt32, &colorMode)) {
    if      ((colorMode == NDColorModeRGB1) && (pOut->dims[0].size != 3))
      pAttribute->setValue(&colorModeMono);
    else if ((colorMode == NDColorModeRGB2) && (pOut->dims[1].size != 3))
      pAttribute->setValue(&colorModeMono);
    else if ((colorMode == NDColorModeRGB3) && (pOut->dims[2].size != 3))
      pAttribute->setValue(&colorModeMono);
  }
  return ND_SUCCESS;
}

/** 返回这个对象当分配的缓存数目 */
int NDArrayPool::getNumBuffers()
{
  return numBuffers_;
}

/**  0=unlimited 返回允许这个对象分配的最大内存字节 */
size_t NDArrayPool::getMaxMemory()
{
  return maxMemory_;
}

/**  返回这个对象当前已经分配的内存字节数 */
size_t NDArrayPool::getMemorySize()
{
  return memorySize_;
}

/** 返回空闲列表中NDArray对象的数目  */
int NDArrayPool::getNumFree()
{
  epicsMutexLock(listLock_);
  int size = (int)freeList_.size();
  epicsMutexUnlock(listLock_);
  return size;
}

/**  删除空闲列表中所有NDArrays */
void NDArrayPool::emptyFreeList()
{
  NDArray *freeArray;
  std::multiset::iterator it; // 获取freeListElement对象的迭代器
  epicsMutexLock(listLock_);
  while (!freeList_.empty()) { 
    it = freeList_.begin(); // 获取第一个freeListElement对象
    freeArray = it->pArray_; // 获取NDArray对象
    freeList_.erase(it);  // 从空闲列表中删除
    memorySize_ -= freeArray->dataSize;
    numBuffers_--;
    delete freeArray;
  }
  epicsMutexUnlock(listLock_);
}

/** 报告NDArrayPool空闲列表尺寸和其它性质。
  * [in] fp : 报告输出的文件指针
  * [in] details : 所要报告的详细程度,当前什么也没做.
  */
int NDArrayPool::report(FILE *fp, int details)
{
  fprintf(fp, "\n");
  fprintf(fp, "NDArrayPool:\n");
  fprintf(fp, "  numBuffers=%d, numFree=%d\n",
         numBuffers_, this->getNumFree()); // 缓存数量,还可分配的内存
  fprintf(fp, "  memorySize=%ld, maxMemory=%ld\n",
        (long)memorySize_, (long)maxMemory_); //已用内存数,最大内存分配数量
  if (details > 5) { // 每个NDArray的信息:NDArray序号,NDArray数据区的尺寸,以及NDArray的地址
    int i;
    std::multiset::iterator it;
    NDArray *freeArray;
    fprintf(fp, "  freeList: (index, dataSize, pArray)\n");
    epicsMutexLock(listLock_);
    for (it=freeList_.begin(),i=0; it!=freeList_.end(); ++it,i++) {
      fprintf(fp, "    %d %d %p\n", i, (int)it->dataSize_, it->pArray_);
    }
    // 每个NDArray的详细信息: NDArray对象的地址 DArray对象的维度数目  
    // NDArray对象每个维度的元素数目  数据类型,数据尺寸,数据地址 唯一id,时间戳 引用计数 属性数目 每个属性信息
    if (details > 10) {
      for (it=freeList_.begin(); it!=freeList_.end(); ++it) {
        freeArray = it->pArray_;
        fprintf(fp, "    Array %d\n", i);
        freeArray->report(fp, details);
      }
    }
    epicsMutexUnlock(listLock_);
  }
  return ND_SUCCESS;
}

NDArrayPool类中方法的测试:

#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 
#include 

#include 

#include 

#include "asynNDArrayDriver.h"
#include "NDArray.h"


int main()
{
        // NDArrayPool::NDArrayPool(class asynNDArrayDriver *pDriver, size_t maxMemory)
        printf("***********Test NDArrayPool construct:*********************\n");
        NDArrayPool * pPool = new NDArrayPool(NULL, 10000);
        printf("NDArrayPool information:\n");
        pPool->report(stdout, 11);
        printf("*************************************************************\n");


        printf("**********************Test NDArrayPool::alloc:***************\n");
        size_t dims[2] = {2,3};
        int ndims = 2;
        NDArray * pArray = pPool->alloc(ndims, dims, NDInt32, 0, NULL);
        printf("NDArray Information:\n");
        pArray->report(stdout, 11);
        printf("NDArrayPool information:\n");
        pPool->report(stdout , 11);
        printf("*************************************************************\n");

        printf("********************Test NDArrayPool::copy:*****************\n");
        NDArrayInfo_t info;
        pArray->getInfo(&info);
        size_t i;
        size_t j;
        printf("Set Value for pArray:\n");
        epicsInt32* pArr = (epicsInt32 *)pArray->pData;
        for (i = 0; i < info.nElements; i++){
                pArr[i] = i;
        }
        printf("copy a new NDArray from pArray:\n");
        NDArray * pArrayout = pPool->copy(pArray, NULL, true, true, true);
        pArrayout->getInfo(&info);
        pArr = (epicsInt32 *)pArrayout->pData;
        printf("xDim = %d, yDim = %d, xSize = %lu, ySize = %lu\n", info.xDim, info.yDim, info.xSize, info.ySize);
        printf("output the values from the new NDArray:\n");
        for (i = 0; i < info.ySize; i++){
                for (j = 0; j < info.xSize; j++){
                        printf("%d\t", pArr[i * info.xSize + j]);
                }
                printf("\n");
        }

        printf("\n");
        printf("New created pArrayout information:\n");
        pArrayout->report(stdout, 11);
        printf("NDArrayPool information:\n");
        pPool->report(stdout ,11);
        printf("*************************************************************\n");

        printf("**********************Test NDArrayPool::reserve**************\n");
        pPool->reserve(pArray);
        printf("NDArray Information:\n");
        pArray->report(stdout, 11);
        printf("*************************************************************\n");


        printf("**********************Test NDArrayPool:release**************\n");
        printf("New created pArrayout information:\n");
        pPool->release(pArrayout);
        pPool->report(stdout ,11);
        printf("*************************************************************\n");

        printf("Use NDArrayPool::alloc to allocate a new NDArray:*************\n");
        dims[0] = 3;
        dims[1] = 2;
        printf("NDArrayPool Information:\n");
        NDArray * pArrayOut = pPool->alloc(ndims, dims, NDFloat64, 0, NULL);
        pArrayOut->report(stdout, 11);
        printf("*************************************************************\n");
        printf("**********************Use NArrayPool::convert***************\n");
        NDArray * pnewNDArray = NULL;
        //int NDArrayPool::convert(NDArray *pIn, NDArray **ppOut, NDDataType_t dataTypeOut, NDDimension_t *dimsOut)
        pPool->convert(pArray, &pnewNDArray, NDFloat64, pArrayOut->dims);
        pnewNDArray->report(stdout, 11);

        epicsFloat64 * pf64 = (epicsFloat64 *)pnewNDArray->pData;

        pnewNDArray->getInfo(&info);
        printf("xDim = %d, yDim = %d, xSize = %lu, ySize = %lu\n", info.xDim, info.yDim, info.xSize, info.ySize);

        for (i = 0; i < info.ySize; i++){
                for (j = 0; j < info.xSize; j++){
                        printf("%f\t", pf64[j + info.xSize * i]);
                }
                printf("\n");
        }
        printf("*************************************************************\n");

        pPool->report(stdout, 11);

        return 0;
}

测试结果如下:

orangepi@orangepi5:~/C_program/host_program/hostApp$ O.linux-aarch64/testNDArrayPool
***********Test NDArrayPool construct:*********************
NDArrayPool information:

NDArrayPool:
  numBuffers=0, numFree=0
  memorySize=0, maxMemory=10000
  freeList: (index, dataSize, pArray)
*************************************************************
**********************Test NDArrayPool::alloc:***************
NDArray Information:

NDArray  Array address=0x558d2d9090:
  ndims=2 dims=[2 3 ]
  dataType=4, dataSize=24, pData=0x558d2d92d0
  uniqueId=0, timeStamp=0.000000, epicsTS.secPastEpoch=0, epicsTS.nsec=0
  referenceCount=1
  number of attributes=0

NDAttributeList: address=0x558d2d9230:
  number of attributes=0
NDArrayPool information:

NDArrayPool:
  numBuffers=1, numFree=0
  memorySize=24, maxMemory=10000
  freeList: (index, dataSize, pArray)
*************************************************************
********************Test NDArrayPool::copy:*****************
Set Value for pArray:
copy a new NDArray from pArray:
xDim = 0, yDim = 1, xSize = 2, ySize = 3
output the values from the new NDArray:
0       1
2       3
4       5

New created pArrayout information:

NDArray  Array address=0x558d2d9310:
  ndims=2 dims=[2 3 ]
  dataType=4, dataSize=24, pData=0x558d2d92f0
  uniqueId=0, timeStamp=0.000000, epicsTS.secPastEpoch=0, epicsTS.nsec=0
  referenceCount=1
  number of attributes=0

NDAttributeList: address=0x558d2d94b0:
  number of attributes=0
NDArrayPool information:

NDArrayPool:
  numBuffers=2, numFree=0
  memorySize=48, maxMemory=10000
  freeList: (index, dataSize, pArray)
*************************************************************
**********************Test NDArrayPool::reserve**************
NDArray Information:

NDArray  Array address=0x558d2d9090:
  ndims=2 dims=[2 3 ]
  dataType=4, dataSize=24, pData=0x558d2d92d0
  uniqueId=0, timeStamp=0.000000, epicsTS.secPastEpoch=0, epicsTS.nsec=0
  referenceCount=2
  number of attributes=0

NDAttributeList: address=0x558d2d9230:
  number of attributes=0
*************************************************************
**********************Test NDArrayPool:release**************
New created pArrayout information:

NDArrayPool:
  numBuffers=2, numFree=1
  memorySize=48, maxMemory=10000
  freeList: (index, dataSize, pArray)
    0 24 0x558d2d9310
    Array 1

NDArray  Array address=0x558d2d9310:
  ndims=2 dims=[2 3 ]
  dataType=4, dataSize=24, pData=0x558d2d92f0
  uniqueId=0, timeStamp=0.000000, epicsTS.secPastEpoch=0, epicsTS.nsec=0
  referenceCount=0
  number of attributes=0

NDAttributeList: address=0x558d2d94b0:
  number of attributes=0
*************************************************************
Use NDArrayPool::alloc to allocate a new NDArray:*************
NDArrayPool Information:

NDArray  Array address=0x558d2d95b0:
  ndims=2 dims=[3 2 ]
  dataType=9, dataSize=48, pData=0x558d2d97f0
  uniqueId=0, timeStamp=0.000000, epicsTS.secPastEpoch=0, epicsTS.nsec=0
  referenceCount=1
  number of attributes=0

NDAttributeList: address=0x558d2d9750:
  number of attributes=0
*************************************************************
**********************Use NArrayPool::convert***************

NDArray  Array address=0x558d2d9830:
  ndims=2 dims=[3 2 ]
  dataType=9, dataSize=48, pData=0x558d2d9a70
  uniqueId=0, timeStamp=0.000000, epicsTS.secPastEpoch=0, epicsTS.nsec=0
  referenceCount=1
  number of attributes=0

NDAttributeList: address=0x558d2d99d0:
  number of attributes=0
xDim = 0, yDim = 1, xSize = 3, ySize = 2
0.000000        1.000000        2.000000
2.000000        3.000000        4.000000
*************************************************************

NDArrayPool:
  numBuffers=4, numFree=1
  memorySize=144, maxMemory=10000
  freeList: (index, dataSize, pArray)
    0 24 0x558d2d9310
    Array 1

NDArray  Array address=0x558d2d9310:
  ndims=2 dims=[2 3 ]
  dataType=4, dataSize=24, pData=0x558d2d92f0
  uniqueId=0, timeStamp=0.000000, epicsTS.secPastEpoch=0, epicsTS.nsec=0
  referenceCount=0
  number of attributes=0

NDAttributeList: address=0x558d2d94b0:
  number of attributes=0

你可能感兴趣的:(EPICS教程,Linux,C,EPICS,C语言)