Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/matlab/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mex文件:如何返回已分配的matlab数组_Matlab_Memory Management_Mex - Fatal编程技术网

Mex文件:如何返回已分配的matlab数组

Mex文件:如何返回已分配的matlab数组,matlab,memory-management,mex,Matlab,Memory Management,Mex,我发现了一个非常棘手的问题,我似乎不容易解决。简而言之,我想从一个mex文件返回一个数组,该数组已作为mex函数输入传递。您可以简单地执行以下操作: void mexFunction(int nargout, mxArray *pargout [ ], int nargin, const mxArray *pargin[]) { pargout[0] = pargin[0]; } 但这不是我需要的。我想从pargin[0]中获取原始指针,对其进行内部处理,并通过设置相应的数据指针返回新创

我发现了一个非常棘手的问题,我似乎不容易解决。简而言之,我想从一个mex文件返回一个数组,该数组已作为mex函数输入传递。您可以简单地执行以下操作:

void mexFunction(int nargout, mxArray *pargout [ ], int nargin, const mxArray *pargin[])
{
   pargout[0] = pargin[0];
}
但这不是我需要的。我想从
pargin[0]
中获取原始指针,对其进行内部处理,并通过设置相应的数据指针返回新创建的mex数组。就像这样:

#include <mex.h>

void mexFunction(int nargout, mxArray *pargout [ ], int nargin, const mxArray *pargin[])
{
  mxArray *outp;
  double *data;
  int m, n;

  /* get input array */
  data = mxGetData(pargin[0]);
  m = mxGetM(pargin[0]);
  n = mxGetN(pargin[0]);

  /* copy pointer to output array */
  outp = mxCreateNumericMatrix(0,0,mxDOUBLE_CLASS,mxREAL);
  mxSetM(outp, m);
  mxSetN(outp, n);
  mxSetData(outp, data);
  /* segfaults with or without the below line */
  mexMakeMemoryPersistent(data);
  pargout[0] = outp;
}
似乎我必须走“未记录的MATLAB”之路,使用
mxCreateSharedDataCopy
mxUnshareArray

您应该使用的方法,这就是记录的方法:

#include "mex.h"

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    plhs[0] = mxDuplicateArray(prhs[0]);
}

虽然没有记录,但MEX API函数
mxCreateSharedDataCopy
ism现在显然被禁止创建
mxArray
的共享数据副本。MathWorks甚至在其解决方案中提供了一个示例

如移除的MathWorks解决方案(1-6NU359)中所述,该函数可用于克隆
mxArray
标头。但是,执行
plhs[0]=prhs[0]之间的差异
plhs[0]=mxCreateSharedDataCopy(prhs[0])
是指第一个版本只是复制
mxArray*
(指针),因此不会创建新的
mxArray
容器(至少在
mexFunction
返回且MATLAB发挥神奇作用之前),这将增加
mxArray
中的数据引用计数

为什么这会是个问题?如果使用
plhs[0]=prhs[0]mexFunction
返回之前,不要对
plhs[0]
进行任何进一步修改,一切都很好,多亏了MATLAB,您将拥有一个共享数据副本。但是,如果在上述分配之后,您在MEX函数中修改了
plhs[0]
,那么也可以在
prhs[0]
中看到更改,因为它引用了相同的数据缓冲区。另一方面,当显式生成共享副本(使用
mxCreateSharedDataCopy
)时,有两个不同的
mxArray
对象,对一个数组的数据进行更改将触发复制操作,从而生成两个完全独立的数组。还有,直接分配

修改的MathWorks示例 从使用上述MathWorks解决方案中修改的
mxsharedcopy.c
的示例开始。第一个重要步骤是为
mxCreateSharedDataCopy
函数提供原型:

>> a.field = [1 2 3];
>> b = pargin_to_pargout(a.field);   % ok - works and assigns [1 2 3] to b
>> pargin_to_pargout(a.field);       % bad - segfault
/*添加此声明,因为它不存在于“mex.h”标题中*/
外部mxArray*mxCreateSharedDataCopy(常量mxArray*pr);
正如注释所述,这不在
mex.h
中,因此您必须自己声明

mxsharedcopy.c
的下一部分通过以下方式创建新的
mxArray
s:

  • 通过
    mxDuplicateArray
    进行深度复制:

    copy1 = mxDuplicateArray(prhs[0]);
    
  • 通过
    mxCreateSharedDataCopy
    共享副本:

    copy2 = mxCreateSharedDataCopy(copy1);
    
  • 我添加的
    mxArray*
    的直接副本:

    copy0 = prhs[0]; // OK, but don't modify copy0 inside mexFunction!
    
  • 然后,它为每个
    mxArray
    及其第一个值打印数据缓冲区的地址(
    pr
    )。以下是针对
    x=one(1e3)修改的
    mxsharedcopy(x)
    的输出

    发生了什么:

  • 正如所料,通过比较
    prhs[0]
    copy0
    我们没有创建任何新的内容,除了指向相同
    mxArray
    的另一个指针之外
  • 比较
    prhs[0]
    copy1
    ,注意
    mxDuplicateArray
    在地址
    721BF120
    处创建了一个新的
    mxArray
    ,并将数据复制到
    19740060
    处的新缓冲区中
  • copy2
    copy1
    具有不同的地址(
    mxArray*
    ),这意味着它也是一个不同的
    mxArray
    ,不仅是由不同变量指向的同一个,而且它们在地址
    19740060
    处共享相同的数据
  • 问题归结为:在
    plhs[0]
    中返回
    copy0
    copy2
    (分别从简单指针复制或
    mxCreateSharedDataCopy
    )是否安全,或者是否有必要使用实际复制数据的
    mxDuplicateArray
    ?我们可以通过销毁
    copy1
    并验证
    copy2
    是否仍然有效来证明
    mxCreateSharedDataCopy
    的有效性:

    mxDestroyArray(copy1);
    copy2val0 = *mxGetPr(copy2); % no crash!
    
    将共享数据副本应用于输入 回到问题上来。这比MathWorks示例更进一步,并返回输入的共享数据副本。只要做:

    if (nlhs>0) plhs[0] = mxCreateSharedDataCopy(prhs[0]);
    
    屏住呼吸

    >> format debug
    >> x=ones(1,2)
    x =
    
    Structure address = 9aff820     % mxArray*
    m = 1
    n = 2
    pr = 2bcc8500                   % double*
    pi = 0
         1     1
    >> xDup = mxsharedcopy(x)
    xDup =
    
    Structure address = 9afe2b0     % mxArray* (different)
    m = 1
    n = 2
    pr = 2bcc8500                   % double* (same)
    pi = 0
         1     1
    >> clear x
    >> xDup % hold your breath!
    xDup =
    
    Structure address = 9afe2b0 
    m = 1
    n = 2
    pr = 2bcc8500                    % double* (still same!)
    pi = 0
         1     1
    
    现在,对于临时输入(不带
    格式调试
    ):

    有趣的是,如果我在没有
    mxCreateSharedDataCopy
    的情况下进行测试(即仅使用
    plhs[0]=prhs[0];
    ),MATLAB不会崩溃,但输出变量永远不会实现:

    >> tempDup = mxsharedcopy(2*ones(1e3)) % no semi-colon
    >> whos tempDup
    >> tempDup(1)
    Undefined function 'tempDup' for input arguments of type 'double'.
    
    R2013b,Windows,64位

    <强> MxSyrdCopy.CPP(修改C++版本):>P/>

    #include "mex.h"
    
    /* Add this declaration because it does not exist in the "mex.h" header */
    extern "C" mxArray *mxCreateSharedDataCopy(const mxArray *pr);
    bool mxUnshareArray(const mxArray *pr, const bool noDeepCopy); // true if not successful
    
    void mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs[])
    {
        mxArray *copy1(NULL), *copy2(NULL), *copy0(NULL);
    
        //(void) plhs; /* Unused parameter */
    
        /* Check for proper number of input and output arguments */
        if (nrhs != 1)
            mexErrMsgTxt("One input argument required.");
        if (nlhs > 1)
            mexErrMsgTxt("Too many output arguments.");
    
        copy0 = const_cast<mxArray*>(prhs[0]); // ADDED
    
        /* First make a regular deep copy of the input array */
        copy1 = mxDuplicateArray(prhs[0]);
    
        /* Then make a shared copy of the new array */
        copy2 = mxCreateSharedDataCopy(copy1);
    
        /* Print some information about the arrays */
        //     mexPrintf("Created shared data copy, and regular deep copy\n");
        mexPrintf("prhs[0] = %X, mxGetPr = %X, value = %lf\n",prhs[0],mxGetPr(prhs[0]),*mxGetPr(prhs[0]));
        mexPrintf("copy0   = %X, mxGetPr = %X, value = %lf\n",copy0,mxGetPr(copy0),*mxGetPr(copy0));
        mexPrintf("copy1   = %X, mxGetPr = %X, value = %lf\n",copy1,mxGetPr(copy1),*mxGetPr(copy1));
        mexPrintf("copy2   = %X, mxGetPr = %X, value = %lf\n",copy2,mxGetPr(copy2),*mxGetPr(copy2));
    
        /* TEST: Destroy the first copy */
        //mxDestroyArray(copy1);
        //copy1 = NULL;
        //mexPrintf("\nFreed copy1\n");
        /* RESULT: copy2 will still be valid */
        //mexPrintf("copy2 = %X, mxGetPr = %X, value = %lf\n",copy2,mxGetPr(copy2),*mxGetPr(copy2));
    
        if (nlhs>0) plhs[0] = mxCreateSharedDataCopy(prhs[0]);
        //if (nlhs>0) plhs[0] = const_cast<mxArray*>(prhs[0]);
    }
    
    #包括“mex.h”
    /*添加此声明,因为它在“mex.h”标题中不存在*/
    外部“C”mxArray*mxCreateSharedDataCopy(常量mxArray*pr);
    bool mxUnshareArray(常量mxArray*pr,常量bool noDeepCopy);//如果不成功,则为true
    void MEX函数(int nlhs、mxArray*plhs[]、int nrhs、const mxArray*prhs[])
    {
    mxArray*copy1(空)、*copy2(空)、*copy0(空);
    //(无效)plhs;/*未使用的参数*/
    /*检查输入和输出参数的正确数量*/
    如果(nrhs!=1)
    mexErrMsgTxt(“需要一个输入参数”);
    如果(nlhs>1)
    mexErrMsgTxt(“太多的输出参数”);
    copy0=const_cast(prhs[0]);//已添加
    /*首先对输入数组进行常规深度复制*/
    copy1=mxDuplicateArray(prhs[0]);
    /*然后创建新阵列的共享副本*/
    copy2=mxCreateSharedDataCopy(copy1);
    /*打印有关阵列的一些信息*/
    //mexPrintf(“创建共享数据副本和常规深度副本”);
    mexPrintf(“prhs[0]
    
    >> tempDup = mxsharedcopy(2*ones(1e3)) % no semi-colon
    >> whos tempDup
    >> tempDup(1)
    Undefined function 'tempDup' for input arguments of type 'double'.
    
    #include "mex.h"
    
    /* Add this declaration because it does not exist in the "mex.h" header */
    extern "C" mxArray *mxCreateSharedDataCopy(const mxArray *pr);
    bool mxUnshareArray(const mxArray *pr, const bool noDeepCopy); // true if not successful
    
    void mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs[])
    {
        mxArray *copy1(NULL), *copy2(NULL), *copy0(NULL);
    
        //(void) plhs; /* Unused parameter */
    
        /* Check for proper number of input and output arguments */
        if (nrhs != 1)
            mexErrMsgTxt("One input argument required.");
        if (nlhs > 1)
            mexErrMsgTxt("Too many output arguments.");
    
        copy0 = const_cast<mxArray*>(prhs[0]); // ADDED
    
        /* First make a regular deep copy of the input array */
        copy1 = mxDuplicateArray(prhs[0]);
    
        /* Then make a shared copy of the new array */
        copy2 = mxCreateSharedDataCopy(copy1);
    
        /* Print some information about the arrays */
        //     mexPrintf("Created shared data copy, and regular deep copy\n");
        mexPrintf("prhs[0] = %X, mxGetPr = %X, value = %lf\n",prhs[0],mxGetPr(prhs[0]),*mxGetPr(prhs[0]));
        mexPrintf("copy0   = %X, mxGetPr = %X, value = %lf\n",copy0,mxGetPr(copy0),*mxGetPr(copy0));
        mexPrintf("copy1   = %X, mxGetPr = %X, value = %lf\n",copy1,mxGetPr(copy1),*mxGetPr(copy1));
        mexPrintf("copy2   = %X, mxGetPr = %X, value = %lf\n",copy2,mxGetPr(copy2),*mxGetPr(copy2));
    
        /* TEST: Destroy the first copy */
        //mxDestroyArray(copy1);
        //copy1 = NULL;
        //mexPrintf("\nFreed copy1\n");
        /* RESULT: copy2 will still be valid */
        //mexPrintf("copy2 = %X, mxGetPr = %X, value = %lf\n",copy2,mxGetPr(copy2),*mxGetPr(copy2));
    
        if (nlhs>0) plhs[0] = mxCreateSharedDataCopy(prhs[0]);
        //if (nlhs>0) plhs[0] = const_cast<mxArray*>(prhs[0]);
    }