c++ - Ciclo de vida de la biblioteca Matlab Mex
(2)
Como mencioné en los comentarios, en Windows podría implementar el punto de entrada DllMain
. Esto se debe a que MEX-file son solo archivos DLL regulares con extensiones diferentes. Aquí hay un ejemplo mínimo:
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%x/n", hModule);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
mexPrintf("DLL_PROCESS_DETACH: hModule=0x%x/n", hModule);
break;
}
return TRUE;
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
mexPrintf("Inside MEX-function/n");
}
Así es como funciona:
>> mex -largeArrayDims testDLL.cpp
>> testDLL
DLL_PROCESS_ATTACH: hModule=0xa0980000
Inside MEX-function
>> testDLL
Inside MEX-function
>> clear testDLL
DLL_PROCESS_DETACH: hModule=0xa0980000
¿Alguien sabe cuál es el ciclo de vida de la biblioteca de matlab mex? Específicamente, estoy interesado en lo siguiente:
- ¿Hay alguna manera de forzar que la biblioteca se cargue antes de invocarla?
- ¿La biblioteca es singleton o hay varias instancias cargadas?
- ¿Hay algún gancho para la inicialización antes de la invocación?
- ¿Hay un gancho / señal de destructor que pueda ser interceptado cuando la biblioteca se descarga para su limpieza?
Hice una búsqueda exhaustiva aquí y en línea y no pude encontrar las respuestas a estas preguntas. Mi problema tiene algún costo de rendimiento con la inicialización y me gustaría evitar eso si es posible, sin necesidad de escribir un servicio.
Un archivo MEX permanece cargado hasta que lo borre ( clear myMexFun
o clear mex
) o salga de MATLAB.
Para la precarga, todo lo que puedo sugerir es llamar a la función sin entradas o con entradas no-equivalentes. He creado sendas de código simples en mi función mexFunction
para manejar tales llamadas sin error, el ejemplo más simple es if(!nrhs) return;
. Las llamadas posteriores no necesitarán cargar el mexFunction
desde el disco (o cualquier otra función en las bibliotecas compartidas llamadas por la función MEX) y no tendrá que preocuparse por el costo de inicialización después de eso.
En cuanto a inicialización / limpieza, constructores / destructores, etc. No conozco ninguna forma de ver lo que está haciendo MATLAB al cargar o descargar el archivo MEX, pero un archivo MEX es una biblioteca común compartida (es decir, DLL / SO) que simplemente exporta una sola función ( mexFunction
es el único punto de entrada ), así que, como señala Amro, puede implementar un DllMain
en Windows para definir el módulo y las operaciones de DllMain
hilos (vea el excelente ejemplo en su respuesta ). No conozco ningún otro mecanismo para interactuar con la biblioteca.
Para realizar tareas cuando el módulo se descarga, puede usar mexAtExit
dentro de mexFunction
para registrarse con MATLAB una función para llamar cuando se descarga la función MEX (de nuevo, borrado o sale de MATLAB). Simplemente defina una función static
en el espacio de nombres global y regístrelo con mexAtExit
. El ejemplo proporcionado por MATLAB (mexatexit.c) demuestra el cierre de un flujo de archivos que se abrió dentro de mexFunction
, pero no se cerró. También puede liberar memoria persistente, cerrar transmisiones, etc. Aquí hay un ejemplo artificial:
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...
}
Cuando se ejecuta:
>> 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
Y usted tiene cierto control sobre la descarga del archivo a través de mexLock
y mexUnlock
.
Lo que sucede con los argumentos (es decir, prhs
, plhs
) cuando la función comienza y vuelve a MATLAB está muy bien documentada , por otro lado, así que supongo que no es eso lo que estás preguntando.
En cuanto a las instancias múltiples, puede intentar usar el Explorador de procesos de Sysinternals (si usa la ventana) para ver qué módulos cargados tienen subprocesos que se ejecutan bajo MATLAB.exe. Solo veo una instancia de un archivo MEX (de un solo hilo) en la lista de hilos, sin importar cuántas veces o con qué rapidez llamo a la función. Sin embargo, una vez que regrese a la línea de comando, puede hacer una version -modules
para ver una lista de módulos cargados, como sugirió Amro. El archivo MEX seguirá allí, y como con la lista de subprocesos visibles por Process Explorer, solo veo una instancia de un determinado archivo MEX.
Gracias, Amro por la entrada. ¡Estoy interesado en ver incluso algunas respuestas más autorizadas a estas preguntas!