10

Does anyone know what the matlab mex library lifecycle is? Specifically I am interested in the following:

  1. Is there a way to force the library to be loaded before invoking it?
  2. Is the library a singleton or are multiple instances loaded?
  3. Are there any hooks for initialization prior to invocation?
  4. Is there a destructor hook/signal that can be intercepted when the library is unloaded for cleanup?

I did an extensive search here and online and I could not find the answers to these questions. My problem has some performance cost with initialization and I would like to avoid that if possible, without needing to write a service.

panos
  • 105
  • 7

2 Answers2

9

A MEX file stays loaded until you clear it (clear myMexFun or clear mex) or quit MATLAB.

For pre-loading, all I can suggest is to call the function with no inputs or with nop-equivalent inputs. I have created simple code paths in my mexFunctions to handle such calls without error, the simplest example being if(!nrhs) return;. Subsequent calls will not need to load the mexFunction from disk (or any other functions in shared libraries called by the MEX function) and you do not need to worry about initialization cost after that.

Regarding initialization/cleanup, constructors/destructors, etc. I am not aware of any way to see what MATLAB is doing when loading or unloading the MEX file, but a MEX file is a regular shared library (i.e. DLL/SO) that just exports a single function (mexFunction is the only entry point), so, as Amro points out, you can implement a DllMain in Windows to define module and thread attach/detach operations (see the excellent example in his answer). I'm not aware of any other mechanisms for interacting with the library.

To perform tasks when the module unloads, you can use mexAtExit within mexFunction to register with MATLAB a function to call when the MEX function unloads (again, cleared or MATLAB exits). Simply define a static function in the global namespace and register it with mexAtExit. The example provided by MATLAB (mexatexit.c) demonstrates closing a file stream that was opened within mexFunction, but not closed. You could also free persistent memory, close streams, etc. Here is a contrived example:

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...
}

When run:

>> 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 

And you have some control over unloading of the file via mexLock and mexUnlock.

What happens to the arguments (i.e. prhs, plhs) when the function starts and returns to MATLAB is very well documented, on the other hand, so I guess that's not what you are asking about.

Regarding multiple instances, you could try using Sysinternals' Process Explorer (if using Window) to have a look at what loaded modules have threads running under MATLAB.exe. I only ever see one instance of a (single threaded) MEX file in threads list no matter how many times or how fast I call the function. However, once back at the command line, you can do version -modules to see a list of loaded modules, as Amro suggested. The MEX file will still be there, and as with the list of threads visible by Process Explorer, I only ever see one instance of a MEX certain file.

Thanks, Amro for the input. I'm interested to see even some more authoritative answers to these questions!

Community
  • 1
  • 1
chappjc
  • 30,359
  • 6
  • 75
  • 132
  • In Windows, MEX-files are really just DLL files with a .mexw32/.mexw64 extension. So you should be able to write the regular [`DllMain`](http://msdn.microsoft.com/en-us/library/windows/desktop/ms682583.aspx) entry function, and handle `DLL_PROCESS_ATTACH`, `DLL_THREAD_ATTACH`,.. notifications. Plus MATLAB provides a documented way to register an exit function: [`mexAtExit`](http://www.mathworks.com/help/matlab/apiref/mexatexit.html). BTW you can use `version -modules` to see a list of all loaded modules instead of using Sysinternals tool. – Amro Dec 13 '13 at 22:40
  • As for managing the lifecycle of a MEX-function, I find that implementing a *switchyard* pattern is a good technique (have the function receive a 'string' as an argument which determine what action to perform, like new/delete/get/set/etc..). You could even make the MEX-function "private" (by placing it inside a `private` folder) and expose its functionality through a MATLAB OOP class, this will give u proper constructor/destructor semantics, especially useful when the MEX file wraps a C++ class (see the [mexopencv](https://github.com/kyamagu/mexopencv) project for an example of this pattern). – Amro Dec 13 '13 at 22:53
  • @Amro Thanks for the input. I forgot about `mexAtExit`. That's pretty relevant, so I added a bit about it, and I've generally improved my answer considering your comments. Great idea about DllMain. I linked to your answer. – chappjc Dec 14 '13 at 00:59
  • 1
    thanks, nice example using `mexAtExit`/`mexMakeMemoryPersistent` +1. btw you are right in that there is only one instance of the MEX module loaded at any time (that would defeat the whole purpose of **shared** libraries otherwise). Not to mention that the entire MX/MEX APIs are [not thread-safe](http://www.mathworks.com/matlabcentral/answers/101658). Even if it were [possible](http://stackoverflow.com/a/1587451/97160), loading multiple copies of the same MEX-function executed in simultaneous threads (inside the same process) would open up a whole new can of worms :) – Amro Dec 14 '13 at 14:49
7

As I mentioned in the comments, in Windows you could implement DllMain entry point. This is because MEX-file are just regular DLL files with different extension. Here is a minimal example:

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");
}

Here is how it works:

>> mex -largeArrayDims testDLL.cpp

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

>> testDLL
Inside MEX-function

>> clear testDLL
DLL_PROCESS_DETACH: hModule=0xa0980000
Amro
  • 123,847
  • 25
  • 243
  • 454
  • For Linux, you could probably use global/static C++ objects to achieve something similar. See this: http://stackoverflow.com/questions/12463718/linux-equivalent-of-dllmain – Amro Dec 13 '13 at 23:10
  • Great example, now linked from my answer. +1 – chappjc Dec 14 '13 at 01:14
  • This is a great answer thank you! I am on Linux, but I can implement a c++ class with a static constructor as pointed out by Amro. Also chappj thanks a lot for the detailed information and examples. I don't know why the system won't let me pick two correct answers. – panos Dec 14 '13 at 06:44
  • @panos No problem, Amro is the real MEX expert. Thanks for the upvote though. Anyway, my example should work in Linux if you remove the `#include ` and replace `NULL` with `(void*)`, although the `mexAtExit` function you register with MATLAB is not as flexible as `DllMain` or a static class constructor & destructor. – chappjc Dec 14 '13 at 07:33
  • I should say that in general, you ought to be [very careful](http://blog.barthe.ph/2009/07/30/no-stdlib-in-dllmai/) about what you put inside your DllMain function: https://www.google.com/search?q=DllMain+site:blogs.msdn.com/b/oldnewthing – Amro Dec 14 '13 at 15:01