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

巧了我就是萌 提交于 2021-01-28 00:19:17

问题


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.


回答1:


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();
    // ...
}



回答2:


It is possible using the new C++ mex interface. Here you can call matlab functions using feval or fevalAsync. fevalAsync is the way to go when calling matlab from another thread.

A function to print to the command window would look like this:

 void print(const std::string& msg)
 {
    mattlab::data::ArrayFactory factory;
    matlabPtr->fevalAsync(u"fprintf", 0,
        std::vector<matlab::data::Array>({ factory.createScalar(msg) }));
 });

The problem however is that the messages are displayed after the mex function has finished. Also subsequent calls like

matlabPtr->evalAsync(u"pause(0.001);");

have no effect. If anyone has an idea, I would also appreciate it.



来源:https://stackoverflow.com/questions/54010898/how-do-you-print-to-console-in-a-multi-threaded-mex-function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!