Matlab:如何从外部API调查已编译的M代码进度? [英] Matlab: How to survey compiled m-code progression from external API?

查看:60
本文介绍了Matlab:如何从外部API调查已编译的M代码进度?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的问题非常特定于matlab编译器和运行时的奥秘.因为只有熟悉matlab运行时API的人才能回答,所以我缩短了很多细节.请让我知道我是否应该更详细.

My question is extremely specific to the arcanes of the matlab compiler and runtime. As only people familiar with matlab runtime API may answer, I shortened much details. Please let me know if I should be more verbose.

使用matlab编译器&运行时,我可以从C#程序中调用用m代码编写的函数.假设致电:

Using the matlab compiler & runtime I can call a function written in m-code from a C# program. Let's say calling:

function [result] = foo(n)
%[
    result = 0;
    for k = 1:n,
        pause(1.0); % simulate long processing
        result = result + 42;
    end
%]

with(在C#代码中某些dllimport的后面):

with (somewhere behind some dllimports in the C# code):

mclFeval(IntPtr inst, string name, IntPtr[] plhs, IntPtr[] prhs)

到目前为止,很好,我对此没有任何问题(即初始化运行时,加载".cft"文件,使用.Net类型来回编组MxArray等)

So far, so good, I have no issue with this (i.e intializing the runtime, loading the '.cft' file, marshalling back and forth MxArray with .Net types, etc...)

我想使用一些cancelprogress回调调查foo函数的进度:

I would like to survey the progression of my foo function using some cancel and progress callbacks:

function [result] = foo(n, cancelCB, progressCB)
%[
    if (nargin < 3), progressCB = @(ratio, msg) disp(sprintf('Ratio = %f, Msg = %s', ratio, msg)); end
    if (nargin < 2), cancelCB = @() disp('Checking cancel...'); end

    result = 0;
    for k = 1:n,

        if (~isempty(cancelCB)), 
            cancelCB(); % Up to the callback to raise some error('cancel');
        end;
        if (~isempty(progressCB)),  
           progressCB(k/n, sprintf('Processing (%i/%i)', k, n));
        end

        pause(1.0); % simulate long processing
        result = result + 42;
    end
%]

但是我当然希望这些回调在C#代码中,而不是在m-one中.

But of course I would like these callbacks to be in the C# code, not within the m-one.

  1. 查看"mclmcr.h"头文件,看来这些功能可能有所帮助:

  1. Looking at 'mclmcr.h' header file, it looks like these functions may be of help:

extern mxArray* mclCreateSimpleFunctionHandle(mxFunctionPtr fcn);
extern bool mclRegisterExternalFunction(HMCRINSTANCE inst, const char* varname, mxFunctionPtr fcn);

不幸的是,这些完全没有文档记录,我发现没有可以模仿的用例来理解它们的工作原理.

Unfortunatly these are fully undocumented and I found no use case I could mimic to understand how they work.

我还考虑过用C#创建一个COM可见对象并将其作为参数传递给Matlab代码:

I've also thought about creating a COM visible object in C# and pass it as a parameter to the matlab code:

// Somewhere within C# code:
var survey = new ComSurvey();
survey.SetCancelCallback =  () => { if (/**/) throw new OperationCancelException(); };
survey.SetProgressCallback = (ratio, msg) => { /* do something */ };

 

function [result] = foo(n, survey)
%[
    if (nargin < 2), survey = []; end

    result = 0;
    for k = 1:n,

        if (~isempty(survey)),
           survey.CheckCancel(); % up to the COM object to raise exception
           survey.SetProgress(k/n, sprintf('Processing... %i/%i', k, n));
        end

        pause(1.0); % simulate long processing
        result = result + 42;
    end
%]

我对创建数字和结构数组的函数非常熟悉,并且知道如何使用它们:

I'm very familiar with functions to create numeric and structure arrays and know how to use them:

extern mxArray *mxCreateNumericArray(...)
extern mxArray *mxCreateStructArray(...)

无论如何,我不知道如何将COM对象打包到MxArrays中?

Anyhow, how COM objects are packaged to MxArrays, I don't know?

进一步调查

第1天

即使仍然不稳定,我还是成功让matlab回调到我的C#代码中,看来mclCreateSimpleFunctionHandle是前进的方向.

Even if still unstable, I succeeded to have matlab to callback into my C# code and it seems that mclCreateSimpleFunctionHandle is the direction to go.

注意:以下代码仅供参考.它可能不适合您自己的情况.稍后,我将提供更简单的代码(即,一旦我获得稳定的解决方案).

  1. mxFunctionPtr的签名,我创建了两个这样的代表:

  1. Looking to the signature of the mxFunctionPtr, I created two delegates like this:

// Mimic low level signature for a Matlab function pointer
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
delegate void MCRInteropDelegate(int nlhs, IntPtr[] plhs, int nrhs, IntPtr[] prhs);

// Same signature (but far more elegant from .NET perspective)
delegate void MCRDelegate(MxArray[] varargouts, MxArray[] varargins);  

  • 我也这样链接到运行时:

  • I also linked to the runtime like this:

    [DllImport("mclmcrrt74.dll", EntryPoint = "mclCreateSimpleFunctionHandle", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
    static extern IntPtr _mclCreateSimpleFunctionHandle(MCRInteropDelegate fctn);
    

  • 假定MxArray是我的.NET类,仅封装了mxArray*句柄,然后我将这样的委托编组:

  • Assuming MxArray is a .NET class of mine that simply encapsulate for mxArray* handles, I then marshaled my delegates like this:

    // Create MxArray from corresponding .NET delegate
    static MxArray CreateFromDelegate(MCRDelegate del)
    {
        // Package high level delegate signature to a 'dllimport' signature
        MCRInteropDelegate interopDel = (nlhs, plhs, nrhs, prhs) =>
        {
            int k = 0;
    
            var varargouts = new MxArray[nlhs];
            var varargins = new MxArray[nrhs];
    
            // (nrhs, prhs) => MxArray[] varargins 
            Array.ForEach(varargins, x => new MxArray(prhs[k++], false)); // false = is to indicate that MxArray must not be disposed on .NET side
    
            // Call delegate
            del(varargouts, varargins); // Todo: varargouts created by the delegate must be destroyed by matlab, not by .NET !!
    
            // MxArray[] varargouts => (nlhs, plhs)
            k = 0;
            Array.ForEach(plhs, x => varargouts[k++].getPointer());
        };
    
        // Create the 1x1 array of 'function pointer' type
        return new MxArray(MCRInterop.mclCreateSimpleFunctionHandle(interopDel));
    }
    

  • 最后,假设moduleMCRModule的一个实例(同样是一类我的类,用于将hInst*封装在低级mclFeval API中),我能够调用foo函数并让它像这样输入我的.NET cancel委托:

  • Finally, assuming module is an instance of MCRModule (again, a class of mine to encapsulate hInst* in low level mclFeval API), I was able to call foo function and have it to enter my .NET cancel delegate like this:

    // Create cancel callback in .NET
    MCRDelegate cancel = (varargouts, varargins) =>
    {
        if ((varargouts != null) && (varargouts.Length != 0) { throw new ArgumentException("'cancel' callback called with too many output arguments"); } 
        if ((varargins != null) && (varargins.Length != 0) { throw new ArgumentException("'cancel' callback called with too many input arguments"); }
    
        if (...mustCancel...) { throw new OperationCanceledException(); }
    }
    
    // Enter the m-code
    // NB: Below function automatically converts its parameters to MxArray
    // and then call low level mclFeval with correct 'mxArray*' handles
    module.Evaluate("foo", (double)10, cancel);
    

    此.NET代码工作正常,并且foo确实正确地回调了cancel委托.

    This .NET code worked fine, and foo really made callback to the cancel delegate properly.

    唯一的问题是它非常不稳定.我的猜测是,我使用了太多的匿名函数,并且其中一些可能为时过早……

    Only problem, is that it is quite unstable. My guess is that I used too many anonymous functions, and probably some of them are disposed too early ...

    将尝试在接下来的几天内提供稳定的解决方案(希望能提供更简单的代码,以便在您自己的环境中进行读取和复制粘贴,以便立即进行测试).

    Will try to provide with stable solution within the next few days (hopefully with simpler code to read and copy-paste in your own context for immediate testing).

    如果您认为我使用mclCreateSimpleFunctionHandle走错了方向,请告诉我.

    Please let me know if you think I'm going the wrong direction with mclCreateSimpleFunctionHandle.

    推荐答案

    知道了

    mclCreateSimpleFunctionHandle实际上是调用正确的API函数,以创建一个数组变量(在matlab方面),该数组变量持有一个函数指针(在外部).现在,我可以编译m代码以回调到我的C#代码中,以进行取消和升级.

    mclCreateSimpleFunctionHandle was effectively the right API function to call at in order to create an array variable (on matlab's side) holding for a function pointer (on external's side). I'm now able to have compiled m-code to call back into my C# code for cancellation and progression purposes.

    此处

    这篇关于Matlab:如何从外部API调查已编译的M代码进度?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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