2

编辑2:问题已解决,请参阅我的答案。

我正在编写一个通过Engine API与 MATLAB 通信的 C++ 程序。C++ 应用程序在 Windows 7 上运行,并与 MATLAB 2012b(32 位)交互。

我想使用 MATLAB 引擎进行耗时的调用engEvalString,但无法弄清楚如何使调用异步。不需要回调(但如果可能的话会很好)。

以下是不起作用的最小示例。

#include <boost/thread.hpp>

extern "C" {
    #include <engine.h>
}

int main()
{
    Engine* eng = engOpen("");
    engEvalString(eng,"x=10");
    boost::thread asyncEval(&engEvalString,eng,"y=5");
    boost::this_thread::sleep(boost::posix_time::seconds(10));
    return 0;
}

运行这个程序后,我切换到 MATLAB 引擎窗口,发现:

» x
x =
    10
» y
Undefined function or variable 'y'.

因此,似乎应该设置 y=5 的第二个调用永远不会被 MATLAB 引擎处理。

线程肯定会运行,您可以通过将engEvalString调用移动到本地函数并将其作为线程启动来检查这一点。

我真的很难过,如果有任何建议,我将不胜感激!

编辑:正如 Shafik 在他的回答中指出的那样,引擎不是线程安全的。我不认为这对我的用例来说应该是一个问题,因为我需要进行的调用相隔约 5 秒,计算需要 2 秒。我等不及这个计算的原因是 C++ 应用程序是一个“中等难度”的实时机器人控制器,它应该以 50Hz 的频率发送命令。如果此速率降至 30Hz 以下,机器人将承担网络问题并关闭连接。

4

2 回答 2

1

所以根据这个 Mathworks 文档,它不是线程安全的,所以我怀疑这会起作用:

http://www.mathworks.com/help/matlab/matlab_external/using-matlab-engine.html

根据本文档,engOpen 派生了一个新进程,它可能会解释您所看到的其余行为:

http://www.mathworks.com/help/matlab/apiref/engopen.html

另请参阅,线程和分叉,三思而后行混合它们:

http://www.linuxprogrammingblog.com/threads-and-fork-think-twice-before-using-them

于 2013-02-26T21:48:50.150 回答
1

所以,我找到了问题所在,但如果有人能解释原因,我会很高兴的!

以下作品:

#include <boost/thread.hpp>

extern "C" {
#include <engine.h>
}

void asyncEvalString()
{
    Engine* eng = engOpen("");
    engEvalString(eng,"y=5");
}

int main()
{
    Engine* eng = engOpen("");
    engEvalString(eng,"x=10");
    boost::thread asyncEvalString(&asyncEvalString);
    boost::this_thread::sleep(boost::posix_time::seconds(1));
    engEvalString(eng,"z=15");
    return 0;
}

如您所见,您需要在新线程中获取指向引擎的新指针。返回的指针与 main 函数中asyncEvalString返回的原始指针不同engOpen,但是两个指针继续运行没有问题:

» x
x =
    10
» y
y =
     5
» z
z =
    15

最后,为了解决线程安全问题,可以围绕 engEvalString 调用设置互斥锁,以确保任何时候只有一个线程使用引擎。也可以修改 asyncEvalString 函数以在 engEvalString 函数完成后触发回调函数。

但是,我希望有人解释上述解决方案为何有效。线程共享进程的堆分配内存,并且可以访问其他线程堆栈上的内存(?),所以我不明白为什么第一个Engine*在单独的线程中使用时突然无效。

于 2013-02-26T22:42:04.633 回答