MATLAB interrupting the algorithm by timer

Hi! I need to set a time limit on an algorithm. I want to throw an error and stop while cycle in try block after 3 seconds, then I want to handle the error in catch block. MATLAB gives me the following diagnostics: Error while evaluating TimerFcn for timer 'timer-2'. Text message 'Error!' is displayed, but error isn't thrown and while cycle is still running. Text message 'Error is caught!' isn't displayed. Could you help me?
t = timer;
t.StartDelay = 3;
t.TimerFcn = @(myTimerObj, thisEvent)error('Error!');
start(t)
a=0;
try
while(1)
if a==1
break;
end
end
stop(t);
delete(t);
catch
stop(t);
delete(t);
disp('Error is caught!')
end

Risposte (3)

Jan
Jan il 18 Dic 2020
Modificato: Jan il 18 Dic 2020
The timer runs in its own thread. The execution of the timer callback is correctly stopped by the error command, but not the regular processing of other Matlab functions.
Which function to you want to interrupt? If it is e.g. an ODE integrator, you can check the value of a flag in the event function:
[value,isterminal,direction] = myEventsFcn(t,y)
position = y(1); % The value that we want to be zero
isterminal = 0; % Halt integration
direction = 0;
Terminator = getappdata(groot, 'TheTerminator');
if Terminator
isterminal = 1;
end
Now you can set this flag by setappdata(groot, 'TheTerminator') from your TIMER callback.
Many builtin functions allow such requests during the processing, but some doesn't. E.g. a huge linear algebra computation cannot be triggered by this method. Then for longer operations it can be an option to start a 2nd instance of Matlab and kill it after a certain time. For a 3 sec limit this will be inefficient, because starting Matlab takes longer already. But for some minutes this would work.
Which operating system are you using?
runtime = java.lang.Runtime.getRuntime();
process = runtime.exec('matlab -nodisplay -nosplash -nodesktop -r "YourFunction; exit"');
pause(100); % Or do what you want
try
exitCode = process.exitValue();
disp('Process has finished.');
catch ME
% Still running...
process.destroy(); % Sorry, I give up
end

4 Commenti

Thank you, Jan! What is ODE integrator?
Maybe, the 2nd MATLAB instance is a good idea.
I use Windows.
An integrator for "ordinary differential equations", e.g.:
doc ode45
This seems to spawn a process faster than trying to start a parpool; and has fewer (different? restirctions... can spawn plots for e.g.)
OK, follow-up question. If I'm using a parfeval I can get the output stream from the subprocess via
f = parfeval(@()disp('hi'), 0)
f.Diary
% ans =
% 'hi
% '
But, how do I do this with "process"? Digging in a bit, it looks like we can get the input stream (what the subprocess puts out...) via:
in_strm = process.getInputStream();
But getting the same kind of "diary" data is a bit involved... and doesn't seem to be working. I pieced together this from another answer from Benjamin Davis:
runtime = java.lang.Runtime.getRuntime();
process = runtime.exec('matlab -nodesktop -nosplash -nodesktop -r "foo; exit"');
% pause(30); % Or do what you want
in_strm = process.getInputStream();
% out_strm = process.getOutputStream();
getMethod_args = javaArray('java.lang.Class',3);
byteArrayName = '[B';
getMethod_args(1) = java.lang.Class.forName(byteArrayName);
getMethod_args(2) = java.lang.Integer.TYPE;
getMethod_args(3) = java.lang.Integer.TYPE;
m_read = in_strm.getClass().getMethod('read',getMethod_args);
read_args = java.util.ArrayList();
% num_available = in_strm.available();
% buf_size = max(1024, num_available);
buf_size = 1024;
buf_ptr = 0;
while process.isAlive()
read_args.add(zeros(1, buf_size, 'int8'));
read_args.add(int32(buf_ptr));
read_args.add(int32(buf_size));
disp('this seems to block...');
n_read = m_read.invoke(in_strm, read_args.toArray());
disp('... this does not print until after the process is killed');
out = char(read_args.get(0));
out = out(:)';
out = out(1:n_read);
disp(out);
buf_ptr = n_read;
fprintf('alive... %s\n', datetime)
pause(1);
end
try
exitCode = process.exitValue();
disp('Process has finished.');
catch ME
% Still running...
process.destroy(); % Sorry, I give up
end
But It the "avaliable" flag is always 0, so I get nothing out... am I barking up the wrong stream?
For completeness, foo.m:
function foo()
for i = 1:10
disp(i);
pause(1);
end
disp('Done');
end

Accedi per commentare.

Joseph Wilson
Joseph Wilson il 14 Dic 2020
Modificato: Walter Roberson il 6 Apr 2023
clear;clc
timerval = tic;
while 1
endval = toc(timerval);
if endval>=3
break
end
end
%tic/toc are built in matlab functions to count time. This utilizes them to count seconds for length of time running through the loop

5 Commenti

If you want to display an error... just replace break with error('Loop took longer than 3 seconds')
Thank you! But if I want to stop running function/code in while block? I can't use tic/toc because I need to stop running function/code immediately, not backdating.
clear;clc
timerval = tic;
while 1
endval = toc(timerval);
f(); % slow code
g(); % slow code
if endval>=3
break
end
end
What I'm doing wrong with timer?
Are those slow functions written by you or are they built in matlab functions that your can't change? If they are written by you, you can add in time checking sections inside those functions to break out of the function if it has taken too long. If they are not able to be editted by you, you might be out of luck with this method.
This is a similar problem if you cannot edit the functions.
I do not think timer has the ability to end a function like you want it to.
Yes, they are built in matlab functions...

Accedi per commentare.

Brian Harris
Brian Harris il 6 Apr 2023
Modificato: Brian Harris il 6 Apr 2023
If you are ok with the limitations of a parfeval call (need parallel processing toolbox, any graphics produced by the calling function are surpressed, ...) you can easily cancel the call without spawning a new matlab instance.
localPool = gcp('nocreate');
if isempty(localPool)
% the parpool is a singlton, so if its not running, start it.
localPool = parpool("local", 2, 'IdleTimeout', 24 * 60);
end
% To get outputs call "fetchOutputs(f)", but this blocks the main thread, so
% instead you can montor f.Result in a killable loop, timer or listener...
f = parfeval(localPool, @pause, 0, Inf);
% for now we'll just kill the execution after 3 seconds
death_clock = timer( ...
'ExecutionMode', 'singleShot', ...
'StartDelay', 3.0, ...
'TimerFcn', @(~, ~)cancel(f) ...
);
% Show the FevalFuture object
disp(f);
fprintf('Started death clock at: %s\n', datetime);
death_clock.start(); % start the death clock
% Monitor for completion/termination
while ~strcmp(f.State, 'finished')
fprintf('waiting to finish... %s\n', datetime);
pause(1);
end
fprintf('Finished... %s\n', datetime);
disp(f);

4 Commenti

you can easily cancel the call without spawning a new matlab instance.
You're spawning new MATLAB instances (roughly, since the workers in the parpool are "MATLAB computational engines that run in the background without a graphical desktop." according to the documentation) with this approach.
Fair point.
Interestingly the Runtime method seems to spawn alot faster than staring up the parallel pool... and can spawn graphics (unlike parfeval). I'll have to give this a try in my app...
You might also be interested in experimenting with the newer backgroundPool and parfeval -- which can be canceled as well. background pools should normally be faster than parpool but have some restrictions on what they can do.
Brian Harris
Brian Harris il 6 Apr 2023
Modificato: Brian Harris il 6 Apr 2023
Thanks Walter. I'll have to give that a shot. Sadly my current project is stuck with R2020a (backgroundPool was introduced in R2021b); will try that out on the next project! Note, using parpool('threads') is supposedly similar, so I'll give that a try; though there are some additonal limitations over the local.

Accedi per commentare.

Categorie

Prodotti

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by