c++ - 如何在多线程 MEX 函数中打印到控制台?
问题描述
我正在编写一个使用 Boost 库的简单生产者消费者 MEX 函数。我已经设法让以下程序正常工作。
#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;
}
mexPrintf()
最大的问题是我尝试在生产者或消费者方法中包含一个MATLAB 只是崩溃。在做了一些调查后,我发现这篇文章解释了这是由于竞争条件而发生的。有谁知道我该如何解决这个问题?我阅读了有关 Mutex 的答案,但我不明白如何实现这样的功能。
解决方案
您不能mexPrintf
从除主线程之外的任何线程调用。互斥锁不会解决您的问题。
MEX API 不是线程安全的
不要在来自 MEX 文件的单独线程上调用 MATLAB® 的单个会话。MEX 和矩阵库 API 不是多线程的。
您可以从 C MEX 文件创建线程;但是,不支持从这些线程访问 MATLAB。不要从衍生线程调用任何 MEX API 函数,包括在头文件
printf
中定义的 。mexPrintf
mex.h
如果您确实需要从这些线程产生输出,请考虑实现一个简单的消息传递系统,其中线程发布带有要输出的文本的消息,并且主线程而不是等待,而是producer_thread.join();
坐在循环中寻找要打印的消息,并用 打印它们mexPrintf
。
下面的代码未经测试。它甚至没有被编译。将其视为伪代码。我认为这是解决方案的合理尝试,但可能有更好的方法。继续自担风险。:)
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();
// ...
}