如何在多线程MEX功能中打印到控制台?

时间:2019-01-02 17:49:10

标签: c++ multithreading matlab boost 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;
}

最大的问题是我试图在生产者或消费者方法MATLAB崩溃时都包含一个mexPrintf()。经过一番调查后,我发现this post解释了这种情况是由于比赛条件而发生的。有谁知道我该如何解决这个问题?我读了关于Mutex的回答,但是我不知道如何实现这种功能。

2 个答案:

答案 0 :(得分:3)

您不能从主线程以外的任何线程调用mexPrintf。互斥锁不能解决您的问题。

来自MATLAB documentation

  

MEX API线程不安全

     

请勿在MEX文件的单独线程上调用MATLAB®的单个会话。 MEX和Matrix库API不是多线程的。

     

您可以从C MEX文件创建线程;但是,不支持从这些线程访问MATLAB。请勿从产生的线程中调用任何MEX API函数,包括printf头文件中定义为mexPrintf的{​​{1}}。

如果您确实需要从这些线程中产生输出,请考虑实现一个简单的消息传递系统,在该系统中,线程将发布带有要输出的文本的消息,而主线程则无需等待mex.h查找要打印的消息的循环,并使用producer_thread.join();进行打印。


下面的代码未经测试。它甚至没有被编译。考虑一下它是伪代码。我认为这是解决方案的合理尝试,但可能会有更好的方法。继续自行承担风险。 :)

mexPrintf

答案 1 :(得分:1)

可以使用新的 C++ mex interface。在这里您可以使用 feval 或 fevalAsync 调用 matlab 函数。 fevalAsync 是从另一个线程调用 matlab 时要走的路。

打印到命令窗口的函数如下所示:

 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);");

没有效果。如果有人有想法,我也会很感激。