MatLab
engine在多线程使用时,由于其本身不是线程安全的,所以需要在同一个线程里创建和使用。比如用户想要在thread1里调用engOpen创建一个MatLab Engine,然后在thread2里利用创建的Engine来调用MatLab函数,这时会出现Engine函数调用无效,即使Engine指针仍然在thread2里正确存在着。
如下:
Class CMatlabMultiThread
{
…
Protected:
Engine *m_pEngine;
//global MatLab engine
pointer
Protected:
void Main_thread();
//caller function for MatLab in main
thread
static void
*entry_new_thread(void
*Param);
//start of subthread
void MatLab_Engine_function();
//in subthread
}
//caller function for MatLab in main
thread
void CMatlabMultiThread::Main_thread()
{
pthread_t thread_id;
m_pEngine = engOpen(NULL); //open a matlab engine
if (m_pEngine ==
NULL)
{
//Error! Fail to connect to MATLAB
engine.
// The plot function will be
disabled!
printf("Fail to open MATLAB
Engine!\n");
exit(0);
}
//this function starts a new thread
and pass this pointer as parameter into the entry func
pthread_create(&thread_id, NULL,
& CMatlabMultiThread::entry_new_thread,
this);
}
//start of subthread
Void * CMatlabMultiThread:: entry_new_thread (void *Param)
{
((CMatlabMultiThread *) Param)->
MatLab_Engine_function();
}
//in subthread
void CMatlabMultiThread::MatLab_Engine_function()
{
engEvalString(m_pEngine, figure);
//through matlab engine to call matlab
function ‘figure’ to creat a new figure
window
//although the pointer m_pEngine
exists and is valid here, it can not function properly
}
如果连同对Engine的初始化都在子线程里完成,比如在MatLab_Engine_function里,那么在子线程里指令执行完后,将释放掉子线程的资源,相当于刚调用完MatLab函数,就调用engClose,这样,诸如用MatLab绘图这样的操作将一闪而过,这不是我们想要的。
然而,如果如上这样在主线程里初始化MatLab
Engine,在子线程里找到Engine指针,然后操作。这时虽然指针存在,但是实际无法进行任何操作。原因可以参加以下网址:http://www.mathworks.com/matlabcentral/fileexchange/349。
我的经验是:
将以上代码改为如下所示:
Class CMatlabMultiThread
{
…
Protected:
Engine *m_pEngine;
//global MatLab engine
pointer
Protected:
void Main_thread();
//caller function for MatLab in main
thread
static void
*entry_new_thread(void
*Param);
//start of subthread
void MatLab_Engine_function();//in
subthread
}
//caller function for MatLab in main
thread
void CMatlabMultiThread::Main_thread()
{
pthread_t thread_id;
int
result;
if ( m_pEngine != NULL
)
{
//in case the engine already exists, close
it
result = engClose(m_pEngine);
m_pEngine = NULL;
}
m_pEngine = engOpen(NULL); //open a matlab
engine
if (m_pEngine ==
NULL)
{
//Error! Fail to connect to MATLAB
engine.
// The plot function will be
disabled!
printf("Fail to open MATLAB
Engine!\n");
exit(0);
}
pthread_create(&thread_id, NULL,
& CMatlabMultiThread::entry_new_thread,
this);
}
//start of subthread
Void * CMatlabMultiThread:: entry_new_thread (void *Param)
{
((CMatlabMultiThread *) Param)->
MatLab_Engine_function();
}
//in subthread
void CMatlabMultiThread::MatLab_Engine_function()
{
//start a MatLab engine again, it dose
not make sense though, but works
m_pEngine =
engOpen(NULL);
if (m_pEngine ==
NULL)
{
//Error! Fail to connect to MATLAB
engine.
// The plot function will be
disabled!
printf("Fail to open MATLAB
Engine!\n");
exit(0);
}
engEvalString(m_pEngine, figure);
//through matlab engine to call matlab
function ‘figure’ to creat a new figure
window
}
即,在主线程里初始化一次MatLab Engine,然后在子线程里再初始化一次。另外,在主线程中调用engOpen之前,先调用一次engClose,这在多次调用MatLab函数中很有用。
虽然这看起来似乎说不通。在调试中可以看到,主线程里调用engOpen时,指针m_pEngine值比如是0x00d01730,此时可以看到MatLab Command Window已经打开。而在子线程里再次调用engOpen时,指针m_pEngine值会变为0x00d01740,m_pEngine值变化了,但是MatLab Command Window还是同一个。然后在函数MatLab_Engine_function中执行
engEvalString(m_pEngine, figure);
创建出一个MatLab绘图窗口。到子线程执行结束后,MatLab绘图窗口和MatLab Command Window都仍然存在。等再次调用主线程Main_thread执行
result = engClose(m_pEngine);
之前可以看到,m_pEngine值仍为0x00d01740,执行之后,返回值result为1,即关闭MatLab
Engine失败,但是MatLab
Command Window和MatLab绘图窗口却都正确的被关闭了,执行engClose(m_pEngine)后,m_pEngine值仍然为0x00d01740,所以为了以后不出现bug,设置为NULL。
看似不应该出现的情况,出现了,而且经严格测试,工作良好。那么,说明这么做一定是有道理的。所以,可以作为MatLab在多线程应用中的一种标准模式。当然,如果谁有更深刻的理解,或更有道理的作法,欢迎致信skpsun@163.com,或直接在日志下面留言。