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