编辑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以下,机器人将承担网络问题并关闭连接。
答案 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*
在单独的线程中使用时突然无效。