Matlab-Mex库生命周期

Matlab Mex library lifecycle

本文关键字:周期 生命 Matlab-Mex      更新时间:2023-10-16

有人知道什么是matlab mex库的生命周期吗?具体来说,我对以下内容感兴趣:

  1. 有没有一种方法可以在调用库之前强制加载它
  2. 库是单实例还是加载了多个实例
  3. 在调用之前是否有任何用于初始化的挂钩
  4. 在卸载库进行清理时,是否有可以截获的析构函数挂钩/信号

我在这里和网上进行了广泛的搜索,但我找不到这些问题的答案。我的问题在初始化方面有一些性能成本,如果可能的话,我希望避免这种情况,而不需要编写服务。

MEX文件将保持加载状态,直到清除它(clear myMexFunclear mex)或退出MATLAB。

对于预加载,我所能建议的就是在没有输入或具有nop等效输入的情况下调用函数。我在mexFunction中创建了简单的代码路径来处理此类调用而不会出错,最简单的例子是if(!nrhs) return;。后续调用将不需要从磁盘加载mexFunction(或MEX函数调用的共享库中的任何其他函数),此后也不需要担心初始化成本。

关于初始化/清理、构造函数/析构函数等。我不知道在加载或卸载MEX文件时,有任何方法可以看到MATLAB在做什么,但MEX文件是一个常规共享库(即DLL/SO),它只导出一个函数(mexFunction是唯一的入口点),所以,正如Amro所指出的,您可以在Windows中实现DllMain来定义模块和线程附加/分离操作(请参阅他的回答中的优秀示例)。我不知道有任何其他与图书馆互动的机制。

要在模块卸载时执行任务,可以使用mexFunction中的mexAtExit向MATLAB注册一个函数,以便在MEX函数卸载时调用(再次清除或MATLAB退出)。只需在全局名称空间中定义一个static函数,并将其注册到mexAtExit。MATLAB提供的示例(mexatexit.c)演示了关闭在mexFunction中打开但未关闭的文件流。您还可以释放持久内存、关闭流等。下面是一个人为的例子:

mexDLLtext.cpp

#include "mex.h"
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
static FILE   *fp=NULL;
static double *pDataC=NULL, *pDataCpp=NULL, *pMxData=NULL;
static char fName[L_tmpnam], counter = 0;
static void CleanUp(void)
{
  fclose(fp);        /* close file opened with fopen */
  free(pDataC);      /* deallocate buffer allocated with malloc/calloc */
  delete[] pDataCpp; /* deallocate buffer allocated with new double[...] */
  mxFree(pMxData);   /* free data created with mx function like mxMalloc */
  mexPrintf("Closing %s and freeing memory...n",fName);
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    if (!fp) { tmpnam(fName); fp = fopen(fName,"w"); }
    fprintf(fp,"%d ",++counter);
    if (!pDataC) pDataC = (double*) malloc(sizeof(double)*16);
    if (!pDataCpp) pDataCpp = new double[16];
    if (!pMxData) {
        pMxData = (double*) mxMalloc(sizeof(double)*16);
        mexMakeMemoryPersistent(pMxData); mexPrintf("First!n");
    }
    mexAtExit(CleanUp);
    // Then use the persistent data...
}

运行时:

>> mex -largeArrayDims mexDLLtest.cpp
>> for i=1:5, mexDLLtest; end
First!
>> clear mexDLLtest
Closing s1rg.1 and freeing memory...
>> type E:s1rg.1
1 2 3 4 5 

您可以通过mexLockmexUnlock控制文件的卸载。

另一方面,当函数启动并返回到MATLAB时,自变量(即prhsplhs)会发生什么,这一点已经有了很好的记录,所以我想这不是你所问的。

关于多个实例,您可以尝试使用Sysinternals的Process Explorer(如果使用Window)来查看哪些加载的模块有在MATLAB.exe下运行的线程。无论我调用函数多少次或多快,我在线程列表中只看到一个(单线程)MEX文件的实例。但是,回到命令行后,您可以按照Amro的建议执行version -modules以查看已加载模块的列表。MEX文件仍将存在,与Process Explorer可见的线程列表一样,我只看到MEX特定文件的一个实例。

谢谢Amro的意见。我很想看看这些问题的更权威的答案!

正如我在评论中提到的,在Windows中可以实现DllMain入口点。这是因为MEX文件只是具有不同扩展名的常规DLL文件。这里有一个最小的例子:

testDLL.cpp

#include "mex.h"
#include <windows.h>
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
{
    switch (dwReason) {
    case DLL_PROCESS_ATTACH:
        mexPrintf("DLL_PROCESS_ATTACH: hModule=0x%xn", hModule);
        break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
        break;
    case DLL_PROCESS_DETACH:
        mexPrintf("DLL_PROCESS_DETACH: hModule=0x%xn", hModule);
        break;
    }
    return TRUE;
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    mexPrintf("Inside MEX-functionn");
}

以下是它的工作原理:

>> mex -largeArrayDims testDLL.cpp
>> testDLL
DLL_PROCESS_ATTACH: hModule=0xa0980000
Inside MEX-function
>> testDLL
Inside MEX-function
>> clear testDLL
DLL_PROCESS_DETACH: hModule=0xa0980000