gpt4 book ai didi

c++ - 通过 Matlab mex 函数调用持久化 C++ 类实例

转载 作者:行者123 更新时间:2023-11-30 05:04:42 27 4
gpt4 key购买 nike

目前正在想办法解决这个问题。

现在我正在尝试为 C++ 库创建 mex 函数,该库通过 Windows 10 PC 上的串行端口与微 Controller 通信,以便我可以在 matlab 中调用该库中的函数。我目前正在研究如何通过多个 matlab mexFunction 调用来保留我的类的实例。

到目前为止,我唯一能想到的就是围绕该类编写一个包装器,声明一个指向我的类实例的全局外部唯一指针,并将其包含在我的 mexFunction() 文件中。

谁能告诉我这是否可行,如果可行,matlab/C++ 究竟如何处理 mexFunction 文件及其方法调用?我不确定我的类实例的范围。

一个具体的例子可能是...

如果我在 .cpp 文件中声明一个指向对象的外部唯一指针并将其包含在我的 mexFunction 文件中,会发生什么情况?在调用多个不同的 mexFunctions 来操作该对象的 matlab 脚本中,指针是否会保持在范围内?

如果我需要重新表述问题或提供更多信息,请告诉我。

最佳答案

是的,你可以做到这一点。如果 MEX 文件都链接到同一个共享库 (DLL),那么它们都可以访问其中定义的全局变量。您需要在共享库中定义您的全局对象,而不是在 MEX 文件之一中。

MEX 文件在第一次执行后保持加载在内存中,直到您调用 clear functions (或 clear all )。当从内存中清除共享对象时,全局对象将被破坏。为防止意外清除您的状态,您可以使用 mexLock 锁定内存中的 MEX 文件之一。 .我建议使用一个“初始化”MEX 文件,它构造对象并将自身锁定在内存中。使用特殊参数,您可以使其解锁并销毁对象。


这是一个例子:

  • libXYZ.dylib/libXYZ.so/XYZ.dll -- 共享库,包含 std::shared_ptr<XYZ> .

  • XYZ_set.mex... -- 初始化 XYZ 的 MEX 文件对象,并将自身锁定在内存中。链接到 libXYZ共享库。

  • XYZ_get.mex... -- 另一个链接到 libXYZ 的 MEX 文件共享库并访问 XYZ由其他 MEX 文件创建的对象。

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 文件仍然可以执行锁定操作,因此它可以保留在调用之间保留的对象。

关于c++ - 通过 Matlab mex 函数调用持久化 C++ 类实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48714244/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com