在Visual Studio中直接调用MATLAB(多线程) [英] Call MATLAB directly (multiple threading) in Visual Studio

查看:315
本文介绍了在Visual Studio中直接调用MATLAB(多线程)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目前我想在Visual Studio中直接调用MATLAB,但似乎无法正常工作。



要清楚,以下面的演示案例为例,即使用MATLAB来计算 2 + 3 。预期结果,即 ans = 5 应打印在 printf(%s\\\
,buf);
,结果是空的。顺便说一下,MATLAB引擎打开( engOpen())成功。

  #include< stdio.h> 
#include< thread>
#includeengine.h

引擎* matlab;

void thread_func()
{
//设置打印缓冲区
char buf [1001];
engOutputBuffer(matlab,buf,1000);

//调用MATLAB
engEvalString(matlab,2 + 3);
printf(%s\\\
,buf); //如果确定,应在命令窗口中打印ans = 5
}

int main()
{
//打开MATLAB引擎
matlab = engOpen(NULL);
if(matlab == NULL){
printf(Error to open MATLAB engine !!! \\\
);
exit(-1);
}

//在这个线程中使用Engine * matlab
std :: thread another_thread(thread_func);

//等待线程完成
another_thread.join();

//关闭MATLAB引擎
engClose(matlab);

return 0;
}

更多信息:




  • MATLAB版本:R2014a x64

  • Visual Studio版本:2013 Professional

  • 项目的构建平台设置为x64。

  • 运行代码时创建了MATLAB命令窗口,这是预期的。


解决方案

这是一个我尝试的简单示例:



test_engine.cpp



  #include< cstdio> 
#includeengine.h

#define BUFSIZE 1000

int main()
{
//打开连接
Engine * matlab = engOpen(NULL);
if(matlab == NULL){
fprintf(stderr,Error to open MATLAB engine\ n);
return EXIT_FAILURE;
}

//输出缓冲区
char buf [BUFSIZE + 1];
buf [BUFSIZE] ='\0';
engOutputBuffer(matlab,buf,BUFSIZE);

//调用MATLAB
engEvalString(matlab,x = magic(5));

printf(Output:\\\
%s\\\
,buf);

//关闭连接
engClose(matlab);

return EXIT_SUCCESS;
}

而不是手动创建Visual Studio项目来编译它,明确声明Engine库不是线程安全(同样的对于MEX-API和MAT-API)。在Windows系统中,独立的引擎程序与外部MATLAB通过 COM 界面进行处理,而使用管道,因为 IPC 机制。



因此,如果创建多线程应用程序,请确保只有一个线程访问引擎应用程序。



注意:仅适用于Windows,还有另一个函数 engOpenSingleUse 。它不同于 engOpen ,因为它创建了一个新的非共享MATLAB引擎会话。这样你可以有多个线程,每个连接到不同的会话(显然工作空间不共享,因为每个会话有一个单独的地址空间)。


Currently I am trying to call MATLAB directly in Visual Studio, but it seems not working.

To be clear, take the following demo case as an example, i.e. use MATLAB to compute 2+3. It is expected that the result, i.e. ans = 5, should be printed in line printf("%s\n", buf);, which turns out to be empty. By the way, the MATLAB engine is opened (engOpen()) successfully.

#include <stdio.h>
#include <thread>
#include "engine.h"

Engine *matlab;

void thread_func()
{
    // set printing buffer
    char buf[1001]; 
    engOutputBuffer(matlab, buf, 1000);

    // call MATLAB
    engEvalString(matlab, "2+3");
    printf("%s\n", buf); // if ok, should print "ans = 5" in the command window
}

int main()
{
    // Open MATLAB engine
    matlab = engOpen(NULL);
    if (matlab == NULL){
        printf("Error to open MATLAB engine!!!\n");
        exit(-1);
    }

    // use "Engine *matlab" in this thread
    std::thread another_thread(thread_func);

    // wait the thread to finish
    another_thread.join();

    // Close MATLAB engine
    engClose(matlab);

    return 0;
}

More info:

  • MATLAB version: R2014a x64
  • Visual Studio version: 2013 Professional
  • The build platform of the project is also set to x64.
  • MATLAB command window is created while running the code, which is expected.

解决方案

Here is a simple example I tried:

test_engine.cpp

#include <cstdio>
#include "engine.h"

#define BUFSIZE 1000

int main()
{
    // open connection
    Engine *matlab = engOpen(NULL);
    if (matlab == NULL) {
        fprintf(stderr, "Error to open MATLAB engine\n");
        return EXIT_FAILURE;
    }

    // output buffer
    char buf[BUFSIZE+1];
    buf[BUFSIZE] = '\0';
    engOutputBuffer(matlab, buf, BUFSIZE);

    // call MATLAB
    engEvalString(matlab, "x = magic(5)");

    printf("Output:\n%s\n", buf);

    // close connection
    engClose(matlab);

    return EXIT_SUCCESS;
}

Instead of manually creating a Visual Studio project to compile it, we can do this right from MATLAB:

>> mbuild test_engine.cpp -llibeng -llibmx

in R2014a and up, we can also use:

>> mex -client engine test_engine.cpp

(assuming you've run mex -setup and mbuild -setup to select a proper C++ compiler, or mex -setup C++ and mex -setup C++ -client MBUILD in R2014a).

Here is the output of the program (I'm running R2014a x64 with VS2013):

C:\> test_engine.exe
Output:
x =
    17    24     1     8    15
    23     5     7    14    16
     4     6    13    20    22
    10    12    19    21     3
    11    18    25     2     9


EDIT:

Here is how to compile the above example in Visual Studio.

  1. Start by creating a new empty "Win32 Console Application" project

  2. Since we're working with MATLAB x64, we need to adjust project configuration to generate 64-bit binaries. From "Build" menu, select "Configuration Manager". From the drop-down menu choose <New> to create a new platform configs, select x64 and accept.

  3. Add the source code from the previous example test_engine.cpp

  4. Next step is tell the VC++ compiler/linker where to find MATLAB headers and libraries. We could do this by setting the project properties.

    A better approach is to create a separate property sheet that can be reused from multiple projects without having to repeat the same settings over and over again. So create the MATLAB_Engine.props property sheet shown below, and add it the project (open the "Property Manager" panel and click the "Add Existing Property Sheet" button).

  5. Finally build the solution and run it (Ctrl+F5)

MATLAB_Engine.props

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ImportGroup Label="PropertySheets" />
  <PropertyGroup Label="UserMacros" />
  <PropertyGroup>
    <LocalDebuggerEnvironment>PATH=C:\Program Files\MATLAB\R2014a\bin\win64;%PATH%$(LocalDebuggerEnvironment)</LocalDebuggerEnvironment>
  </PropertyGroup>
  <ItemDefinitionGroup>
    <ClCompile>
      <AdditionalIncludeDirectories>C:\Program Files\MATLAB\R2014a\extern\include;C:\Program Files\MATLAB\R2014a\extern\include\win64</AdditionalIncludeDirectories>
      <PreprocessorDefinitions>IBMPC</PreprocessorDefinitions>
    </ClCompile>
    <Link>
      <AdditionalLibraryDirectories>C:\Program Files\MATLAB\R2014a\extern\lib\win64\microsoft</AdditionalLibraryDirectories>
      <AdditionalDependencies>libmx.lib;libmex.lib;libmat.lib;libeng.lib;mclmcrrt.lib</AdditionalDependencies>
    </Link>
  </ItemDefinitionGroup>
  <ItemGroup />
</Project>

(this is intended for MATLAB R2014a on a 64-bit Windows. Adjust the path if you installed MATLAB to a different location)

The output as expected:

Tip: if you are testing an engine program repeatedly, then each time it runs a new MATLAB process opens up and closes in the background. To make things easier during development, you could start a normal MATLAB session, and execute the command below to tell it to act like as an Automation server. That way all Engine programs will run in this same session which remains open.

>> enableservice('AutomationServer',true);


EDIT2:

The MATLAB documentation explicitly states that the Engine library is not thread-safe (same goes for the MEX-API and the MAT-API). In Windows systems, standalone Engine programs communicate with the external MATLAB process through a COM interface, while it uses pipes on Linux/Mac systems as IPC mechanism.

So if you create multi-threaded applications, make sure only one thread accesses the engine application.

Note: For Windows only, there is another function engOpenSingleUse. It differs from engOpen in that it creates a new non-shared MATLAB engine session. That way you can have multiple threads each connected to a different session (obviously workspace is not shared, because each session has a separate address space).

这篇关于在Visual Studio中直接调用MATLAB(多线程)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆