问题
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