本文介绍了Matlab:在COM服务器中运行一个函数而不阻塞matlab?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Matlab 64位R2011b,我必须使用32位版本(我安装了R2010b)来命令一个硬件(32位dll)。为此,我创建了一个COM服务器 actxserver(),它工作。





我在下面的脚本中简化了我的问题:如果你在一个32位会话的时候,64位会话变得忙碌有两个Matlab版本安装,你可以尝试我的代码,看到我的问题。



用一句话:




  • 一个按钮启动一个计时器,自开始以来所经过的时间

  • 另一个按钮在64位会话中暂停2秒(没有坏影响),随后在32位会话中暂停2秒(错误的效果:计时器停止!)



任何建议都可以防止阻止64位会话。 >

注意:我安装了并行计算工具箱,但从未使用过。 parfeval()函数未在R2011b Matlab版本中实现(以防万一有用)。

  function timer_test 
%handles
ha = [];
%为Matlab创建COM服务器32位(相应地更改版本)
ha.matlab32bits = actxserver('Matlab.Application.7.11');
%如果已经打开,创建或实现figure --------------------------
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); %将数字转换为前面
clf%清除所有图形对象
end

%按钮-------------------- -----------------------------------------
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} ...%指定回调
);

%Text ---------------------------------------- -----------------------
ha.text1 = uicontrol('Style','Text'...
,'位置',[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'));
%暂停64位matlab(定时器仍然运行,ok)
set(ha.text2,'String','Paused in 64bits');
pause(2);
%暂停32位matlab(定时器停止!!)
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);


解决方案

timer + pause 是一个(特别的)误导性的情况,你不应该期望所有操作都有相同的非阻塞行为。



毕竟,MATLAB是一个单线程执行环境(而是我称之为核心引擎/解释器的部分),即使它有许多其他背景线程用于各种目的,如UI或I / O。拥有专用的UI线程,认为Java 对于在长时间操作期间保持IDE响应非常重要。



暂停呼叫期间,某些活动。因此,它不是一个模拟重计算负荷的完美方法。



据我所知,,这些定时器对象发出类型的Java事件, 暂停期间。因此,您的定时器回调函数仍然被调用,这反过来更新GUI生成更多的HG事件,也允许在暂停期间执行 ...



现在,如果用实际消耗活动CPU时间的函数调用替换64位版本的 pause(2) (例如计算一个巨大矩阵的特征值),你会注意到定时器回调不再在指定的时间间隔上执行。



从64位MATLAB过程,调用具有相同的性质(在COM服务器中调用的方法),这也会阻塞执行线程。



在这两种情况下,你可以尝试最大化图形窗口这样的调用,你会看到,即使窗口重绘信息没有被及时发送由




p>这里是我的版本的编码修改,以显示这两种情况都可以阻止MATLAB执行(本地函数调用当前MATLAB过程或远程函数调用其他MATLAB过程使用COM自动化):

 函数timer_test 
%h是与嵌套函数共享的句柄结构
h = create_gui();
h.actx = actxserver('Matlab.Application8.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

函数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);
执行(h.actx,'pause(5);');
toc
end
set(h.btns,'Enable','on')

%reset text
set(h.txt2,串',''); drawow
end

函数timer_cb(〜,〜)
如果图被关闭,%abort
如果〜ishghandle(h.fig)
try stop h.timer); delete(h.timer); end
return
end

%更新计数器
set(h.txt1,'String',sprintf('%d',h.timer.TasksExecuted))
drawnow
end

function handles = create_gui()
%构建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

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);
解决方案

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

这篇关于Matlab:在COM服务器中运行一个函数而不阻塞matlab?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

11-02 08:49