问题
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 asmexPrintf
in themex.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