首页 > 解决方案 > 如何在多线程 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 的答案,但我不明白如何实现这样的功能。

标签: c++multithreadingmatlabboostmex

解决方案


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

MATLAB 文档

MEX API 不是线程安全的

不要在来自 MEX 文件的单独线程上调用 MATLAB® 的单个会话。MEX 和矩阵库 API 不是多线程的。

您可以从 C MEX 文件创建线程;但是,不支持从这些线程访问 MATLAB。不要从衍生线程调用任何 MEX API 函数,包括在头文件printf中定义的 。mexPrintfmex.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();
    // ...
}

推荐阅读