Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multithreaded (pthreads) MATLAB mex function causes MATLAB to crash after exiting

I have a task that I need to perform in MATLAB many times, and I would like to reduce the amount of time taken to perform the task by using a multithreaded MEX function. However, I'm running into a little snag where the MEX function causes MATLAB to crash after exiting due to a double free or corruption error.

The task itself is quite large, but I have been able to reproduce the error with the following minimum (non)working example:

#include <pthread.h>
#include "mex.h"
#include "matrix.h"

/* hard coded number of matrices to create per thread */
int num_mat = 10;

/* struct for passing information to the thread */
typedef struct {
    int pnum;
    int num_mat;
    mxArray *outMatrix;
} pt_info_t;


/* thread function */
void *doThread(void *tinfo){

    /* extract info from the struct */
    pt_info_t pinfo = *((pt_info_t *)tinfo);
    mxArray *outMatrix = pinfo.outMatrix;

    /* create a cell matrix */
    mxArray *one_cell = mxCreateCellMatrix(pinfo.num_mat, 1);
    int i = 0;
    for(i = 0; i < pinfo.num_mat; i++){
        /* fill the cell matrix with 1x1 double matrices */
        mxArray *one_mat = mxCreateDoubleMatrix(1,1,mxREAL);
        mxSetCell(one_cell, i, one_mat);
    }

    /* add the cell matrix to the return cell matrix */
    mxSetCell(outMatrix, pinfo.pnum, one_cell);

    /* exit the thread */
    pthread_exit(NULL);
}

/* thread entry function */
void t_comp_routine(int num_threads, mxArray *outMatrix){

    /* thread setup */
    pthread_t threads[num_threads];
    pt_info_t pinfo[num_threads];

    /* add information to the thread info structs and start threads */
    int pnum = 0;
    for(pnum = 0; pnum < num_threads; pnum++){
        pinfo[pnum].pnum = pnum;
        pinfo[pnum].num_mat = num_mat;
        pinfo[pnum].outMatrix = outMatrix;

        pthread_create(&threads[pnum], NULL, doThread, (void *)(pinfo + pnum));
    }

    /* join the threads */
    for(pnum = 0; pnum < num_threads; pnum++){
        pthread_join(threads[pnum], NULL);
    }


}

/* same routine but without threads */
void comp_routine(int num_pretend_threads, mxArray *outMatrix){

    int pnum = 0;
    for(pnum = 0; pnum < num_pretend_threads; pnum++){
        mxArray *one_cell = mxCreateCellMatrix(num_mat, 1);

        int i = 0;
        for(i = 0; i < num_mat; i++){
            mxArray *one_mat = mxCreateDoubleMatrix(1,1,mxREAL);
            mxSetCell(one_cell, i, one_mat);
        }

        mxSetCell(outMatrix, pnum, one_cell);
    }
}

/* The gateway function 
* nlhs = NUM left hand side args (OUTPUT)
* nrhs = NUM rhs args (INPUT)
* plhs = array of output args (OUTPUT)
* prhs = array of input args (INPUT)
*/
void mexFunction(int nlhs, mxArray *plhs[],
                 int nrhs, const mxArray *prhs[])
{    
    int num_threads = mxGetScalar(prhs[0]);
    mxArray *outMatrix = mxCreateCellMatrix(num_threads, 1);

    /* t_comp_routine causes matlab to crash after exiting */
    t_comp_routine(num_threads, outMatrix);

    /* comp_routine does not */
    /* comp_routine(num_threads, outMatrix); */

    plhs[0] = outMatrix;
    printf("Finished!\n");
}

The program takes in a num_threads variable and outputs a cell array with the same number of elements as there are threads. Each cell of the output array is a cell matrix of length 10, with each element of that containing a 1x1 double matrix.

Calling the function with 10 threads causes the following:

>> thread_test(10)
Finished!
ans = 
    {10x1 cell}
    {10x1 cell}
    {10x1 cell}
    {10x1 cell}
    {10x1 cell}
    {10x1 cell}
    {10x1 cell}
    {10x1 cell}
    {10x1 cell}
    {10x1 cell}
*** glibc detected *** /usr/local/MATLAB/R2013a/bin/glnxa64/MATLAB: double free or corruption (fasttop): 0x00002b89a000cf10 ***

I have excluded the Backtrace for brevity, but I am more than happy to provide it if required.

Occasionally, calling the function with less than 10 threads will complete without showing an error, although I suspect that there may still be a problem. The non threaded function comp_routine performs the same task and has run many times without error.

I believe the error may be as a result of creating mxArrays inside the thread function, but I don't know how to remedy this as with the full program I would have to create these arrays on the fly (I don't always know ahead of time what size to create them for example).

like image 336
agnussmcferguss Avatar asked Nov 16 '25 19:11

agnussmcferguss


1 Answers

The MEX API (includes the mx* functions) is NOT thread safe (MathWorks Support Team). You can only call mx*/mex* functions from the main MATLAB thread, with a few exceptions (see bottom). In doThread, which is launched with pthread_create, you are calling several functions that can't be used there:

  • mxCreateCellMatrix
  • mxCreateDoubleMatrix
  • mxSetCell

You will have to pass plain-old-data in and out of doThread and manage the cell array outside of the threads called with pthread_create. In addition to the example from MathWorks, which demonstrates using the Windows API for multithreading, another nice example of multithreading a MEX function using both Pthreads and the Windows API is provided by Dirk-Jan Kroon in his tutorial on the File Exchange and his non-rigid registration submission, among others. It may also be worth checking out the C++11 approach using std::thread in the MexThread submission.

Exceptions (YMMV): mexErrMsgIdAndTxt.

like image 90
chappjc Avatar answered Nov 19 '25 08:11

chappjc