Как вы печатаете на консоли в многопоточной MEX-функции? - PullRequest
0 голосов
/ 02 января 2019

Я пишу простую потребительскую функцию MEX производителя, которая использует библиотеку Boost.Мне удалось заставить следующую программу работать без каких-либо проблем.

#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, но я не понимаю, как бы я реализовал такую ​​функциональность.

1 Ответ

0 голосов
/ 02 января 2019

Вы не можете вызвать mexPrintf из любого потока, кроме основного потока. Мьютекс не решит вашу проблему.

Из документации MATLAB :

MEX API не безопасен для потоков

Не вызывать один сеанс MATLAB® в отдельных потоках из файла MEX. API MEX и Matrix Library не являются многопоточными.

Вы можете создавать темы из файла 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();
    // ...
}
...