ang*_*nor 5 matlab memory-management mex
我发现了一个非常棘手的问题,我似乎无法轻易解决这个问题.简而言之,我想从一个mex文件返回一个数组,该数组已作为mex函数输入传递.你可以琐碎地做到这一点:
void mexFunction(int nargout, mxArray *pargout [ ], int nargin, const mxArray *pargin[])
{
pargout[0] = pargin[0];
}
Run Code Online (Sandbox Code Playgroud)
但这不是我需要的.我希望得到原始指针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;
}
Run Code Online (Sandbox Code Playgroud)
它不起作用.我得到一个段错误,如果没有立即,然后几个电话后.我相信文档中没有关于这种情况的说法.唯一的要求是data指针已被分配使用mxCalloc,显然它有.因此,我认为这段代码是合法的.
我需要这样做,因为我正在将一个复杂的MATLAB结构解析为我的内部C数据结构.我处理数据,一些数据被重新分配,有些则没有.我想透明地返回输出结构,而不必考虑何时只需复制mxArray(第一个代码片段),以及何时我必须创建它.
请帮忙!
编辑
在进一步查看和讨论Amro后,似乎我的第一个代码片段不受支持,并且在某些情况下可能导致MATLAB崩溃,例如,在将结构字段或单元格元素传递给此类mex函数时:
>> 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
Run Code Online (Sandbox Code Playgroud)
看来我将不得不沿着"未记载的MATLAB"道路前进并使用mxCreateSharedDataCopy和mxUnshareArray.
您应该使用mxDuplicateArray,这是记录的方式:
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
plhs[0] = mxDuplicateArray(prhs[0]);
}
Run Code Online (Sandbox Code Playgroud)
而无证,所述MEX API函数mxCreateSharedDataCopy 是被给定为一个溶液通过MathWorks公司,现在显然否认,用于创建的一个共享的数据拷贝mxArray.MathWorks甚至在其解决方案中提供了一个示例mxsharedcopy.c.
如删除的MathWorks解决方案(1-6NU359)中所述,该函数可用于克隆mxArray标头.然而,do plhs[0] = prhs[0];和之间的区别在于plhs[0] = mxCreateSharedDataCopy(prhs[0]);第一个版本只复制mxArray*(一个指针),因此不会创建一个新的mxArray容器(至少在mexFunction返回和MATLAB工作之前不会产生魔力),这会增加两个数据的引用计数mxArray秒.
为什么这可能是一个问题?如果您在返回之前使用plhs[0] = prhs[0];并且不做进一步修改,那么一切都很好,并且由于MATLAB,您将拥有共享数据副本.但是,如果在MEX函数中修改了上述赋值后,也可以看到更改,因为它引用了相同的数据缓冲区.另一方面,当显式生成共享副本(with )时,有两个不同的对象,对一个数组的数据的更改将触发复制操作,从而产生两个完全独立的数组.此外,在某些情况下,直接分配会导致分段错误.plhs[0]mexFunctionplhs[0] prhs[0]mxCreateSharedDataCopymxArray
从使用mxsharedcopy.c上面引用的MathWorks解决方案中修改过的示例开始.第一个重要步骤是为mxCreateSharedDataCopy函数提供原型:
/* Add this declaration because it does not exist in the "mex.h" header */
extern mxArray *mxCreateSharedDataCopy(const mxArray *pr);
Run Code Online (Sandbox Code Playgroud)
正如评论所述,这不是mex.h,所以你必须自己声明.
下一部分通过以下方式mxsharedcopy.c创建新mxArray的:
深刻的副本mxDuplicateArray:
copy1 = mxDuplicateArray(prhs[0]);
Run Code Online (Sandbox Code Playgroud)共享副本通过mxCreateSharedDataCopy:
copy2 = mxCreateSharedDataCopy(copy1);
Run Code Online (Sandbox Code Playgroud)直接复制的mxArray*,由我添加:
copy0 = prhs[0]; // OK, but don't modify copy0 inside mexFunction!
Run Code Online (Sandbox Code Playgroud)然后它pr为每个mxArray及其第一个值打印数据缓冲区()的地址.下面是修改后的输出mxsharedcopy(x)为x=ones(1e3);:
prhs[0] = 72145590, mxGetPr = 18F90060, value = 1.000000
copy0 = 72145590, mxGetPr = 18F90060, value = 1.000000
copy1 = 721BF120, mxGetPr = 19740060, value = 1.000000
copy2 = 721BD4B0, mxGetPr = 19740060, value = 1.000000
Run Code Online (Sandbox Code Playgroud)
发生了什么:
prhs[0]和copy0我们没有创建任何新的东西,除了另一个指向相同的指针mxArray.prhs[0]并copy1注意mxDuplicateArray创建一个新的mxArrayat地址721BF120,并将数据复制到新的缓冲区中19740060.copy2有一个不同的地址(mxArray*)copy1,意味着它也是一个不同的mxArray不仅是不同变量指向的相同,但它们都在地址共享相同的数据19740060.现在的问题简化为:它是安全的返回plhs[0]任一copy0或copy2(从简单的指针复制或mxCreateSharedDataCopy分别),或者是有必要使用mxDuplicateArray,这实际上将数据复制?我们可以证明,mxCreateSharedDataCopy通过销毁copy1和验证copy2仍然有效:
mxDestroyArray(copy1);
copy2val0 = *mxGetPr(copy2); % no crash!
Run Code Online (Sandbox Code Playgroud)
回到问题.比MathWorks示例更进一步,返回输入的共享数据副本.做就是了:
if (nlhs>0) plhs[0] = mxCreateSharedDataCopy(prhs[0]);
Run Code Online (Sandbox Code Playgroud)
屏住呼吸!
>> 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
Run Code Online (Sandbox Code Playgroud)
现在进行临时输入(不format debug):
>> tempDup = mxsharedcopy(2*ones(1e3));
>> tempDup(1)
ans =
2
Run Code Online (Sandbox Code Playgroud)
有趣的是,如果我没有测试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'.
Run Code Online (Sandbox Code Playgroud)
R2013b,Windows,64位.
mxsharedcopy.cpp(修改后的C++版本):
#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]);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3609 次 |
| 最近记录: |