异步调用MATLAB的engEvalString

时间:2013-02-26 20:30:38

标签: c++ api matlab

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

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

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

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

#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以下,机器人将承担网络问题并关闭连接。

2 个答案:

答案 0 :(得分: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

答案 1 :(得分: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;
}

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

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

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

然而,我会感谢有人解释为什么上述解决方案有效。线程共享进程的堆分配内存,并且可以访问其他线程堆栈(?)上的内存,因此我无法理解为什么第一个Engine*在单独的线程中使用时突然无效。