Matlab : running a function in a COM server without blocking matlab?

三世轮回 提交于 2019-12-07 14:18:08

问题


I'm working on Matlab 64-bits R2011b, and I have to use a 32-bits version (I have R2010b installed) to command a hardware (32-bit dll). For that, I created a COM server with actxserver() and it works.

However, whenever a function takes time in the 32-bit session, the 64-bit session becomes 'busy' and nothing works anymore until completion.

I simplified my problem in the script below : if you have two Matlab versions installed, you can try my code and see my problem.

In a few words :

  • one button starts a timer that simply shows the time elapsed since it was started
  • the other button makes a 2 seconds pause in the 64-bit session (no bad effect), followed by a 2 seconds pause in the 32-bit session (bad effect : the timer halts !).

Any advice would be appreciated to prevent blocking the 64-bit session.

NB : I have the parallel computing toolbox installed but never used it yet. The parfeval() function wasn't implemented in the R2011b Matlab version (in case it would have been useful).

function timer_test
% handles
ha=[];
% create COM server for Matlab 32 bits (change the version accordingly)
ha.matlab32bits = actxserver('Matlab.Application.7.11');
% Create or actualize figure if already open--------------------------
alreadyOpenHandle=findall(0,'Name','TimerTest');
if isempty(alreadyOpenHandle)
    ha.f=figure('Position',[400 400 200 140]...
        ,'Name','TimerTest'...
        ,'NumberTitle','Off'...
        ,'MenuBar','none'...
        ,'Color',[0.94 0.94 0.94] ...
        );
else
    ha_Old=guidata(alreadyOpenHandle);
    ha.f=ha_Old.f;
    figure(ha.f);                   % Bring figure to front
    clf                             % Clear all graphics objects
end

% Buttons-------------------------------------------------------------
ha.button1=uicontrol('Style','Togglebutton' ...
    ,'Position',[20 80 80 40] ...
    ,'Parent',ha.f ...
    ,'String','Run Timer' ...
    ,'Callback',@button1_Callback ...
    );
ha.button2=uicontrol('Style','Pushbutton' ...
    ,'Position',[100 80 80 40] ...
    ,'Parent',ha.f ...
    ,'String','Pause' ...
    ,'Callback',@button2_Callback ...
    );

% Timer--------------------------------------------------------------
ha.myTimer = timer('ExecutionMode', 'fixedRate' ... 
    ,'Period', 0.1 ...
    ,'TasksToExecute',1000 ...
    ,'TimerFcn', {@myTimerFcn,ha.f} ... % Specify callback
    );

% Text---------------------------------------------------------------
ha.text1=uicontrol('Style','Text' ...
    ,'Position',[40 20 50 40] ...
    ,'String','0 s' ...
    );
ha.text2=uicontrol('Style','Text' ...
    ,'Position',[120 20 50 40] ...
    ,'String','-' ...
    );

guidata(ha.f,ha);

%====================================================================

function button1_Callback(hO,ev)
ha=guidata(findall(0,'Name','TimerTest'));
if get(ha.button1,'Value')==1
    start(ha.myTimer);
else
    stop(ha.myTimer);
end


function button2_Callback(hO,ev)
ha=guidata(findall(0,'Name','TimerTest'));
% pause the 64-bit matlab (timer still running, ok)
set(ha.text2,'String','Paused in 64bits');
pause(2);
% pause the 32-bit matlab (timer halts !!)
set(ha.text2,'String','Paused in 32bits');
drawnow;
ha.matlab32bits.Execute('pause(2)');
% end
set(ha.text2,'String','-');


function myTimerFcn(obj,ev,f)
drawnow;
ha=guidata(findall(0,'Name','TimerTest'));
elapsed=[num2str(roundn(obj.TasksExecuted/10,-1),'%4.1f') ' s'];
set(ha.text1,'string',elapsed);

回答1:


The combination of timer + pause is a (special) misleading case, and you should not expect the same non-blocking behavior from all operations.

After all, MATLAB is a single-threaded execution environment (rather the part which I refer to as the core engine/interpreter), even though it has many other background threads used for various purposes such as UI or I/O. Having a dedicated UI thread, think Java EDT, is important to keep the IDE responsive during long operations.

During a pause call, certain events continue to be processed (such as window repainting messages, HG callbacks, Java events), while the execution is halted. For this reason, it is not a perfect way to simulate heavy computation load.

As far as I know, MATLAB timers are implemented in Java, and these timer objects emit Java events of the kind that are listened-to and processed during a pause period. Thus your timer callback function was still being called, which in turn updates the GUI generating more HG events that are also permitted to execute during a pause...

Now if you replace the pause(2) of the "64-bit version" with a function call that actually consume active CPU time (say computing the eigenvalues of a huge matrix), you will notice that the timer callback is no longer being executed on the specified intervals.

From the point of view of the "64-bit MATLAB" process, the ha.matlab32bits.Execute call is of the same nature (a method invoked in a COM server) which will also block the execution thread.

In both cases, you could try to maximize the figure window such calls, and you will see that even window repaint message are not being promptly dispatched by the event loop, on account of the main thread being busy running those long operations.


Here is my version of the coded modified to show that both cases can block MATLAB execution (either local function called on the current MATLAB process or a remote function called on the other MATLAB process using COM automation):

function timer_test
    % h is a handles structure shared with the nested functions
    h = create_gui();
    h.actx = actxserver('Matlab.Application.8.2');
    h.timer = timer('ExecutionMode', 'fixedRate', 'Period',0.1, ...
        'BusyMode','drop', 'TasksToExecute',1000, 'TimerFcn',@timer_cb);

    function toggle_btn_cb(o,~)
        % start/stop timer
        if get(o, 'Value') == 1
            start(h.timer);
        else
            stop(h.timer);
            set(h.txt1, 'String','0'); drawnow
        end
    end

    function run_btn_cb(~,~,mode)
        set(h.btns, 'Enable','off')
        if strcmp(mode,'local')
            % local call
            set(h.txt2, 'String','Locally'); drawnow
            tic
            eig(rand(2000));
            toc
        elseif strcmp(mode,'remote')
            % remote call
            set(h.txt2, 'String','Remotely'); drawnow
            tic
            %Feval(h.actx, 'pause', 0, 5);
            Execute(h.actx, 'pause(5);');
            toc
        end
        set(h.btns, 'Enable','on')

        % reset text
        set(h.txt2,'String',''); drawnow
    end

    function timer_cb(~,~)
        % abort if figure was closed
        if ~ishghandle(h.fig)
            try stop(h.timer); delete(h.timer); end
            return
        end

        % update counter
        set(h.txt1, 'String',sprintf('%d', h.timer.TasksExecuted))
        drawnow
    end

    function handles = create_gui()
        % build the GUI
        hfig = figure('Menu','none', 'Position',[400 400 275 140]);
        uicontrol('Style','togglebutton', 'String','Start/Stop', ...
            'Parent',hfig, 'Position',[20 80 80 40], ...
            'Callback',@toggle_btn_cb);
        hbtn1 = uicontrol('Style','pushbutton', 'String','Local Call', ...
            'Parent',hfig, 'Position',[100 80 80 40], ...
            'Callback',{@run_btn_cb,'local'}, 'Interruptible','on');
        hbtn2 = uicontrol('Style','pushbutton', 'String','Remote Call', ...
            'Parent',hfig, 'Position',[180 80 80 40], ...
            'Callback',{@run_btn_cb,'remote'}, 'Interruptible','on');
        htxt1 = uicontrol('Style','text', 'String','0', ...
            'Parent',hfig, 'Position',[50 20 60 20]);
        htxt2 = uicontrol('Style','text', 'String','', ...
            'Parent',hfig, 'Position',[130 20 100 20]);
        handles = struct('fig',hfig, 'btns',[hbtn1,hbtn2], ...
            'txt1',htxt1, 'txt2',htxt2);
    end

end



来源:https://stackoverflow.com/questions/24368424/matlab-running-a-function-in-a-com-server-without-blocking-matlab

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!