如何在多线程 MEX 函数中打印到控制台?
How do you print to console in a Multi-Threaded MEX Function?
我正在编写一个使用 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 就崩溃了。在做了一些调查后,我发现 this post 这解释了这是由于竞争条件而发生的。有谁知道我该如何解决这个问题?我读了关于 Mutex 的答案,但我不明白我将如何实现这样的功能。
您不能从主线程以外的任何线程调用 mexPrintf
。互斥量不能解决您的问题。
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.
如果您确实需要从这些线程生成输出,请考虑实现一个简单的消息传递系统,其中线程 post 一条包含要输出的文本的消息和主线程,而不是等待 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();
// ...
}
可以使用新的 C++ mex interface。在这里您可以使用 feval 或 fevalAsync 调用 matlab 函数。 fevalAsync 是从另一个线程调用 matlab 时的方法。
打印命令 window 的函数如下所示:
void print(const std::string& msg)
{
mattlab::data::ArrayFactory factory;
matlabPtr->fevalAsync(u"fprintf", 0,
std::vector<matlab::data::Array>({ factory.createScalar(msg) }));
});
但问题是消息是在 mex 函数完成后显示的。还有后续调用,例如
matlabPtr->evalAsync(u"pause(0.001);");
没有效果。如果有人有想法,我也将不胜感激。
我正在编写一个使用 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 就崩溃了。在做了一些调查后,我发现 this post 这解释了这是由于竞争条件而发生的。有谁知道我该如何解决这个问题?我读了关于 Mutex 的答案,但我不明白我将如何实现这样的功能。
您不能从主线程以外的任何线程调用 mexPrintf
。互斥量不能解决您的问题。
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.
如果您确实需要从这些线程生成输出,请考虑实现一个简单的消息传递系统,其中线程 post 一条包含要输出的文本的消息和主线程,而不是等待 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();
// ...
}
可以使用新的 C++ mex interface。在这里您可以使用 feval 或 fevalAsync 调用 matlab 函数。 fevalAsync 是从另一个线程调用 matlab 时的方法。
打印命令 window 的函数如下所示:
void print(const std::string& msg)
{
mattlab::data::ArrayFactory factory;
matlabPtr->fevalAsync(u"fprintf", 0,
std::vector<matlab::data::Array>({ factory.createScalar(msg) }));
});
但问题是消息是在 mex 函数完成后显示的。还有后续调用,例如
matlabPtr->evalAsync(u"pause(0.001);");
没有效果。如果有人有想法,我也将不胜感激。