当MATLAB文件到达mxSetPr时,MATLAB崩溃 [英] MATLAB crashes when it reaches mxSetPr in a mex file

查看:93
本文介绍了当MATLAB文件到达mxSetPr时,MATLAB崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在mex文件中编写一个调用MATLAB函数的函数.不幸的是,当涉及到mxSetPr时,MATLAB崩溃,并且无法继续进行.有人可以告诉我如何解决这个问题吗?

I am writing a function within in a mex file which calls a MATLAB function. Unfortunately, when it comes to mxSetPr, MATLAB crashes and does not proceed further. Could someone kindly tell me how I can fix this?

void myconv2( double * Ain  , double *Aout, 
              int AnRows    , int AnCols, 
              double* kernel, int kernelnRows, int kernelnCols )
{

    mxArray *rhs[3], *lhs[1];

    rhs[0] = mxCreateNumericMatrix( 0, 0, mxDOUBLE_CLASS, mxREAL );
    rhs[1] = mxCreateNumericMatrix( 0, 0, mxDOUBLE_CLASS, mxREAL );
    rhs[2] = mxCreateString       ( "same" );

    mxSetPr( rhs[0], Ain    );
    mxSetM ( rhs[0], AnRows );
    mxSetN ( rhs[0], AnCols );


    mxSetPr( rhs[1], kernel      );
    mxSetM ( rhs[1], kernelnRows );
    mxSetN ( rhs[1], kernelnCols );


    mexCallMATLAB(1, lhs, 3, rhs, "conv2");
    Aout = mxGetPr( lhs[0] );

}

推荐答案

传递给mxSetPr的内存必须使用mxMallocmxCalloc分配,而不是使用mallocnew等分配. mxSetPr文档页面:

The memory passed to mxSetPr must be allocated with mxMalloc or mxCalloc, NOT with malloc, new, etc. From the mxSetPr docs page:

void mxSetPr(mxArray *pm, double *pr);
...
pr

void mxSetPr(mxArray *pm, double *pr);
...
pr

指向数组的第一个元素的指针.数组中的每个元素都包含值的实部.该数组必须位于动态内存中; 调用mxCalloc分配此内存.请勿使用ANSI®C calloc函数,否则会导致内存对齐问题,从而导致程序终止.如果pr指向静态内存,则可能导致内存泄漏和其他内存错误.

Pointer to the first element of an array. Each element in the array contains the real component of a value. The array must be in dynamic memory; call mxCalloc to allocate this memory. Do not use the ANSI® C calloc function, which can cause memory alignment issues leading to program termination. If pr points to static memory, memory leaks and other memory errors can result.

另一个问题是您对myconv2的声明,其中输出参数为double *Aout.在函数内部,Aout本身已被修改,Aout最初指向的内容(如果有的话)没有被修改.若要修改指针,请按引用传递(double *&Aout),或传递双指针(double **Aout)并更改您的调用约定.如果您使用C ++进行编译,则最容易使用参考.

Another issues is with your declaration for myconv2, where the output argument is double *Aout. Inside the function, Aout itself is modified, not whatever Aout originally points to, if anything. To modify the pointer, either pass by reference (double *&Aout), or pass a double pointer (double **Aout) and change your calling convention. Its easiest to use a reference if you are compiling as C++.

这将使您跳过mxSetPr命令并允许您运行mexCallMATLAB,但是下一个问题是plhs[1]指向的mxArray是在myconv2 ,这意味着它会在程序终止后随时由MATLAB内存管理器释放.您应该将数据从lhs[1]中复制到Aout中(我想这就是您想要的,因为您按值传递了指针),或者将Aout分配给myconv2之外的mxMallocmxCalloc

This will get you past the mxSetPr commands and allow you to run mexCallMATLAB, but the next issue is that the mxArray pointed to by plhs[1] is created inside myconv2, which means it will be deallocated by the MATLAB memory manager whenever it likes after the program termination. You should either copy the data out of lhs[1] and into Aout (I think this is what you want since you pass the pointer by value) or allocate Aout outside of myconv2 with mxMalloc or mxCalloc.

mxSetPr与创建被分配mxArray*的函数不同的功能带来的另一个有趣的惊喜是,当myconv2存在时,MATLAB还将尝试销毁rhs[]中的每个mxArray.假设您希望调用方负责这些数组,然后在myconv2退出之前将指针设置为NULL.我以前从未遇到过这种情况,但这可能是一种有效的方法.

Another fun surprise with having mxSetPr in a different function from the one that created the mxArray* being assigned is that when myconv2 exists, MATLAB will also try to destroy each mxArray in rhs[]. Assuming you want the caller to be responsible for these arrays, then set the pointers to NULL before myconv2 exits. I've never had come across this situation before, but this might be a valid approach.

myconv

#include "mex.h"

void myconv2(double * Ain, double *Aout,
    int AnRows, int AnCols,
    double* kern, int kernelnRows, int kernelnCols)
{
    mxArray *rhs[3], *lhs[1];

    rhs[0] = mxCreateNumericMatrix(0, 0, mxDOUBLE_CLASS, mxREAL);
    rhs[1] = mxCreateNumericMatrix(0, 0, mxDOUBLE_CLASS, mxREAL);
    rhs[2] = mxCreateString("same");

    mxSetPr(rhs[0], Ain);
    mxSetM(rhs[0], AnRows);
    mxSetN(rhs[0], AnCols);

    mxSetPr(rhs[1], kern);
    mxSetM(rhs[1], kernelnRows);
    mxSetN(rhs[1], kernelnCols);

    mexCallMATLAB(1, lhs, 3, rhs, "conv2");

    // prevent `Ain` and `kern` from being destroyed on `myconv2` return
    mxSetPr(rhs[0], NULL); mxSetPr(rhs[1], NULL);

    // copy each element of output
    double *d = mxGetPr(lhs[0]);
    for (int i = 0; i < AnRows*AnCols; ++i)
        Aout[i] = d[i];

}

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    int nrows = 256, ncols = 256;
    double *Aout = new double[nrows * ncols];

    // allocate with `mxMalloc`
    double *Ain = (double*)mxMalloc(nrows * ncols * sizeof(double));
    double *kern = (double*)mxMalloc(5 * 5 * sizeof(double));

    myconv2(Ain, Aout, nrows, ncols, kern, 5, 5);

    // free here, not in `myconv2`
    mxFree(Ain);
    mxFree(kern);

    // do something with Aout
    mexPrintf("%p\n", Aout);

    delete[] Aout;
}


myconv2之外创建lhs以避免任何复制


Creating lhs outside of myconv2 to avoid any copies

void myconv2(double *Ain, mxArray *&lhs, int AnRows, int AnCols,
    double *kern, int kernelnRows, int kernelnCols)
{
    mxArray *rhs[3];

    rhs[0] = mxCreateNumericMatrix(0, 0, mxDOUBLE_CLASS, mxREAL);
    rhs[1] = mxCreateNumericMatrix(0, 0, mxDOUBLE_CLASS, mxREAL);
    rhs[2] = mxCreateString("same");

    mxSetPr(rhs[0], Ain);
    mxSetM(rhs[0], AnRows);
    mxSetN(rhs[0], AnCols);

    mxSetPr(rhs[1], kern);
    mxSetM(rhs[1], kernelnRows);
    mxSetN(rhs[1], kernelnCols);

    mexCallMATLAB(1, &lhs, 3, rhs, "conv2");

    mxSetPr(rhs[0], NULL); mxSetPr(rhs[1], NULL);
}

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    mxArray *AoutMX;

    int nrows = 256, ncols = 256;
    double *Ain = (double*)mxMalloc(nrows * ncols * sizeof(double));
    double *kern = (double*)mxMalloc(5 * 5 * sizeof(double));

    myconv2(Ain, AoutMX, nrows, ncols, kern, 5, 5);

    mxFree(Ain); mxFree(kern);

    // do something with AoutMX
    mexPrintf("%x\n", mxGetPr(AoutMX));    
}

尽管要特别注意,当您调用conv2时,即使您使用相同的mxArray* ,它也会始终创建一个新的mxArray.

Although, it's important to note that when you call conv2, it always creates a new mxArray, even if you use the same mxArray*.

为完整起见,值得注意的是,有一些低级技巧可以让您分配任何指针(不仅是使用mxMallocmxCalloc创建的指针),而且还涉及猜测不透明类型并执行类似以下操作:

For completeness, it is worth noting that there are low-level hacks that let you assign any pointer (not just those created with mxMalloc and mxCalloc), but these involve guessing the structure of the opaque type mxArray and doing something like ths:

// effectively, mxSetPr(mxmat, Pr + n); 
((mxArray_type_guess*)(mxmat))->data.number_array.pdata = (Pr + n);

请参见 InplaceArray FEX提交了解更多信息.但是,mxArray结构猜测可能已严重过时.假设您可以使用此确定正确的结构代码.

See the InplaceArray FEX submission for more info. The mxArray struct guesses are probably badly out of date though. Supposedly you can determine the right structure with this code.

这篇关于当MATLAB文件到达mxSetPr时,MATLAB崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆