Search code examples
c++multithreadingmatlabboostmex

How do you print to console in a Multi-Threaded MEX Function?


I'm writing a simple producer consumer MEX function which uses the Boost library. I have manged to get the following program to work without any issues.

#include "mex.h"
#include <boost/thread/thread.hpp>
#include <boost/lockfree/spsc_queue.hpp>
#include <iostream>
#include <boost/atomic.hpp>

int producer_count = 0;
boost::atomic_int consumer_count (0);
boost::lockfree::spsc_queue<int, boost::lockfree::capacity<1024> > spsc_queue;
const int iterations = 10000000;

void producer()
{
    for (int i = 0; i != iterations; ++i) {
        int value = ++producer_count;
        while (!spsc_queue.push(value));
    }
}

boost::atomic<bool> done (false);

void consumer()
{
    int value;
    while (!done) {
        while (spsc_queue.pop(value))
            ++consumer_count;
    }

    while (spsc_queue.pop(value))
        ++consumer_count;
}

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    if (!spsc_queue.is_lock_free())
    {
      mexPrintf("boost::lockfree::queue is not lockfree\n");
      mexEvalString("drawnow;");
    }
    else
    {
      mexPrintf("boost::lockfree::queue is lockfree\n");
      mexEvalString("drawnow;");
    }

    boost::thread producer_thread(producer);
    boost::thread consumer_thread(consumer);

    producer_thread.join();
    done = true;
    consumer_thread.join();

    cout << "produced " << producer_count << " objects." << endl;
    cout << "consumed " << consumer_count << " objects." << endl;
}

The big problem is I try to include a mexPrintf() into the either the producer or consumer method MATLAB just crashes. After doing some investigation I found this post which explained this happens because of race conditions. Does anyone know how I can fix this issue? I read what the answer said about Mutex, but I do not understand how I would implement such a functionality.


Solution

  • You cannot call mexPrintf from any thread except the main thread. A mutex will not solve your problem.

    From the MATLAB documentation:

    MEX API Is Not Thread Safe

    Do not call a single session of MATLAB® on separate threads from a MEX file. The MEX and Matrix Library APIs are not multi-threaded.

    You can create threads from a C MEX file; however, accessing MATLAB from those threads is not supported. Do not call any MEX API functions from the spawned threads, including printf, which is defined as mexPrintf in the mex.h header file.

    If you really need to produce output from these threads, consider implementing a simple messaging system where the threads post a message with the text to be output, and the main thread, instead of waiting with producer_thread.join();, sits in a loop looking for messages to print, and prints them with mexPrintf.


    The code below is not tested. It's not even been compiled. Consider it pseudo-code. I think this is a reasonable attempt at a solution but there might be much better approaches. Continue at your own risk. :)

    boost::lockfree::queue<std::string> message_queue;
    
    void producer() {
        //...
        message_queue.push("A string to print!");
        //...
    }
    
    void mexFunction( /*...*/ ) {
        // ...
        boost::thread producer_thread(producer);
        boost::thread consumer_thread(consumer);
        while(producer_thread.joinable()) {
            join_for(boost::chrono::milliseconds(50));
            std::string s;
            while (message_queue.pop(s)) {
                mexPrintf("%s\n", s.c_str());
            }
        }
        producer_thread.join();
        done = true;
        consumer_thread.join();
        // ...
    }