是的,您可以这样做。如果 MEX 文件都链接到同一个共享库 (DLL),那么它们都可以访问其中定义的全局变量。您需要在共享库中定义全局对象,而不是在 MEX 文件之一中。
MEX 文件在首次执行后一直加载到内存中,直到您调用 clear functions(或 clear all)。当共享对象从内存中清除时,全局对象将被破坏。为防止意外清除您的状态,您可以使用 mexLock 锁定内存中的 MEX 文件之一。我建议使用一个“初始化” MEX 文件,该文件构造对象并将自身锁定在内存中。使用特殊参数,您可以使其自行解锁并销毁对象。
这是一个例子:
libXYZ.dylib / libXYZ.so / XYZ.dll -- 一个共享库,包含一个std::shared_ptr<XYZ>。
XYZ_set.mex... -- 一个 MEX 文件,用于初始化 XYZ 对象,并将自身锁定在内存中。指向libXYZ 共享库的链接。
XYZ_get.mex... -- 另一个 MEX 文件,它链接到 libXYZ 共享库并访问由另一个 MEX 文件创建的 XYZ 对象。
XYZ_lib.h:
#include <memory>
#include <iostream>
struct XYZ {
XYZ(double a);
~XYZ();
double get();
private:
double a_;
};
extern std::unique_ptr<XYZ> XYZ_data;
XYZ_lib.cpp:
#include "XYZ_lib.h"
std::unique_ptr<XYZ> XYZ_data;
XYZ::XYZ(double a) : a_(a) {
std::cout << "Constructing XYZ with " << a_ << '\n';
}
XYZ::~XYZ() {
std::cout << "Destructing XYZ, value was " << a_ << '\n';
}
double XYZ::get() {
return a_;
}
XYZ_set.cpp:
#include "XYZ_lib.h"
#include <mex.h>
/// \brief An output stream buffer for MEX-files.
///
/// Creating an object of this class replaces the stream buffer in `std::cout` with the newly
/// created object. This buffer will be used as long as the object exists. When the object
/// is destroyed (which happens automatically when it goes out of scope), the original
/// stream buffer is replaced.
///
/// Create an object of this class at the beginning of any MEX-file that uses `std::cout` to
/// print information to the *MATLAB* terminal.
class streambuf : public std::streambuf {
public:
streambuf() {
stdoutbuf = std::cout.rdbuf( this );
}
~streambuf() {
std::cout.rdbuf( stdoutbuf );
}
protected:
virtual std::streamsize xsputn( const char* s, std::streamsize n ) override {
mexPrintf( "%.*s", n, s );
return n;
}
virtual int overflow( int c = EOF ) override {
if( c != EOF ) {
mexPrintf( "%.1s", &c );
}
return 1;
}
private:
std::streambuf* stdoutbuf;
};
void mexFunction( int, mxArray*[], int nrhs, const mxArray* prhs[] ) {
streambuf buf; // Allows std::cout to work in MEX-files
// Always do lots of testing for correct input in MEX-files!
if (nrhs!=1) {
mexErrMsgTxt("Requires 1 input");
}
if (mxIsChar(prhs[0])) {
// Assume it's "-unlock" or something like that. Unlock MEX-file
mexUnlock();
std::cout << "XYZ can now be cleared from memory\n";
} else {
// Here we create new data
if (!mxIsDouble(prhs[0]) || mxIsEmpty(prhs[0])) {
mexErrMsgTxt("Expected double input");
}
double a = *mxGetPr(prhs[0]);
XYZ_data = std::unique_ptr<XYZ>(new XYZ(a));
// If the MEX-file is not locked, lock it
if (!mexIsLocked()) {
mexLock();
}
}
}
(对不起这里的streambuf 类,它是噪音,但我想使用它,以便您可以看到共享库中的构造函数和析构函数被调用。)
XYZ_get.cpp:
#include "XYZ_lib.h"
#include <mex.h>
void mexFunction( int, mxArray* plhs[], int, const mxArray* [] ) {
if (XYZ_data) {
plhs[0] = mxCreateDoubleScalar(XYZ_data->get());
} else {
mexErrMsgTxt("XYZ not initialized!");
}
}
编译:
在 shell 中(我使用的是 MacOS,因此使用了 dylib 扩展名,根据需要进行调整):
g++ -std=c++11 -Wall -fpic XYZ_lib.cpp -shared -o libXYZ.dylib
在 MATLAB 中:
mex XYZ_set.cpp libXYZ.dylib
mex XYZ_get.cpp libXYZ.dylib
跑步:
>> XYZ_get
Error using XYZ_get
XYZ not initialized!
>> XYZ_set(4)
Constructing XYZ with 4
>> XYZ_set(6)
Constructing XYZ with 6
Destructing XYZ, value was 4
>> XYZ_get
ans =
6
>> clear all
>> XYZ_set -unlock
XYZ can now be cleared from memory
>> clear all
Destructing XYZ, value was 6
如您所见,XYZ_get 访问由new 由XYZ_set 编辑的对象中的值。 clear all 通常会从内存中清除所有内容,但锁定的 MEX 文件会保留在这里。 XYZ_set -unlock 使用字符串参数调用它,这会导致它自行解锁。 clear all 现在也从内存中清除该 MEX 文件,现在 XYZ 对象被销毁。
我需要在这里提一下,C++ 没有一致的 ABI,这些 MEX 文件只有在共享库使用相同的编译器编译时才会加载。
另一种方法(通常更简单)是只创建一个 MEX 文件(与您的 C++ 代码静态链接)和一堆调用 MEX 文件的 M 文件。 M 文件提供了很好的界面(也可以进行输入检查),MEX 文件位于private/ 目录中,没有人可以弄乱它。 MEX 文件仍然可以执行锁定操作,因此它可以保留在调用之间保留的对象。