Жизненный цикл библиотеки Matlab Mex

Кто-нибудь знает, что такое жизненный цикл библиотеки matlab mex? В частности, меня интересует следующее:

  • Есть ли способ заставить библиотеку загружаться до ее вызова?
  • Является ли библиотека одиночной или загружена несколькими экземплярами?
  • Есть ли крючки для инициализации перед вызовом?
  • Есть ли крючок/сигнал деструктора, который может быть перехвачен, когда библиотека выгружается для очистки?

Я сделал обширный поиск здесь и в Интернете, и я не мог найти ответы на эти вопросы. Моя проблема связана с некоторыми затратами на инициализацию, и я хотел бы избежать этого, если это возможно, без необходимости писать службу.

Ответ 1

Как я уже упоминал в комментариях, в 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%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");
}

Вот как это работает:

>> mex -largeArrayDims testDLL.cpp

>> testDLL
DLL_PROCESS_ATTACH: hModule=0xa0980000
Inside MEX-function

>> testDLL
Inside MEX-function

>> clear testDLL
DLL_PROCESS_DETACH: hModule=0xa0980000

Ответ 2

Файл MEX остается загруженным до тех пор, пока вы его не очистите (clear myMexFun или clear mex) или закройте MATLAB.

Для предварительной загрузки все, что я могу предложить, это вызвать функцию без входов или с эквивалентными входами. Я создал простые кодовые пути в моем mexFunction для обработки таких вызовов без ошибок, самым простым примером является if(!nrhs) return;. Последующие вызовы не должны загружать mexFunction с диска (или любые другие функции в разделяемые библиотеки, вызываемые функцией MEX), и после этого вам не нужно беспокоиться об стоимости инициализации.

Относительно инициализации/очистки, конструкторов/деструкторов и т.д. Мне неизвестно, как MATLAB делает это при загрузке или выгрузке файла MEX, но MEX файл является обычной общей библиотекой (то есть DLL/SO) который просто экспортирует одну функцию (mexFunction - единственная точка входа), поэтому, как отмечает Amro, вы можете реализовать DllMain в Windows для определения операций по подключению и отсоединению модулей и потоков (см. отличный пример в его ответе). Я не знаю других механизмов взаимодействия с библиотекой.

Для выполнения задач при выгрузке модуля вы можете использовать mexAtExit в mexFunction для регистрации в 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 

И у вас есть некоторый контроль над выгрузкой файла через mexLock и mexUnlock.

Что происходит с аргументами (т.е. prhs, plhs) при запуске функции и возвращается в MATLAB очень хорошо документировано, с другой стороны, поэтому я думаю, что не то, о чем вы просите.

Что касается нескольких экземпляров, вы можете попробовать использовать Проводник процессов Sysinternals (если использовать Window), чтобы посмотреть, какие загруженные модули имеют потоки работает под MATLAB.exe. Я вижу только один экземпляр (однопоточный) MEX файл в списке нитей независимо от того, сколько раз или как быстро я вызываю функцию. Однако, вернувшись в командной строке, вы можете сделать version -modules, чтобы увидеть список загруженных модулей, как предложил Амро. Файл MEX все равно будет присутствовать, и, как и в списке потоков, видимых в Process Explorer, я вижу только один экземпляр файла MEX.

Спасибо, Amro для ввода. Мне интересно видеть еще более авторитетные ответы на эти вопросы!