Stop an app designer callback thread like the debugger does?

It is evident that whenever the user clicks a button in an app designer app, the callback is called in a new thread. The debugger takes advantage of this, the red "stop" square button obviously terminates the currently running callback thread. Very clean, very effective.
Now, is there any way that I as a programmer can do the same thing? Here's my problem. I'm building a scientific analysis program, and the users have a lot of options. The wrong options combined with the wrong data can produce a VERY long-running computation, and the user has no good way of getting out of it. Indeed, my users are tending to click extra buttons, setting yet more computations in motion, and it ends up in a meltdown.
So, can I kill the thread, or do I just have to put checkpoints in all my long-running code and check for a stop variable?

Answers (1)

"It is evident that whenever the user clicks a button in an app designer app, the callback is called in a new thread."
No, the current thread is interrupted, pushing the location onto the stack, and the callback is run in the same thread. At the end of execution of the callback, the old information is popped and execution is resumed.
The entire execution is on a single thread, unless background pool is used or unless one of the facilities of the Parallel Computing Toolbox are used. (Well, graphics runs on a seperate thread.)
(The single thread used is distinct from threads that manage the user interface.)

8 Comments

Yes, but our observation has been that if the user presses a second button before the first one has completed its long running execution, things happen concurrently.
Furthermore, the following happens:I press a button, the callback starts executing, and lands in the debugger at a breakpoint. Without resolving that, I press a second button, its callback starts executing, and lands in the debugger at a breakpoint. I find that I have to press the red square Stop button twice to clear it.Without multiple threads, how could this be?
Here is the core of a very simple app which I just tested. It just contains two buttons. The calculate button displays a series of numbers. It takes a few seconds. If, while that is going, I press the hello button, the word "hello" appears in the middle of the output. This can be repeated multiple times. If this is not a demonstration of multi-threaded architecture, please tell me what is actually going on behind the scenes! It sure seems like it!
methods (Access = public)
function calculate(app, p)
sum = 0;
for i = 1:1000000000
sum = sum + i^p;
test = mod(i,10000000);
if test == 0
disp(i/10000000)
drawnow;
end
end
end
end
% Callbacks that handle component events
methods (Access = private)
% Button pushed function: calculateButton
function calculateButtonPushed(app, event)
app.calculate(2)
end
% Button pushed function: helloButton
function helloButtonPushed(app, event)
disp("hello")
end
end
The calculate function runs. The hello button interrupts the calculate function, runs the hello, and resumes the calculate function. Single threaded for app execution (plus a thread for monitoring the user interface, following cursor movement and so on.)
Ok, not actually using threads, but still, we have two concurrent tasks running. Back to the original question. Is there any way that Task 2, instead of printing "hello", can forcibly stop Task 1? or force it to get an exception, or something? Obviously the debugger has this power, is it by any means available to the ordinary programmer?
This would be really, really valuable for giving control back to my user when things have gotten out of hand.
There is one concurrent task that is monitoring the cursor movement. There is one concurrent task that is controlling the debugger. There is one concurrent task that is handling all of the execution of the app.
When the button is pushed, the current thread is interrupted -- at the beginning of each line of MATLAB code, MATLAB internally checks whether an interrupt has been requested, and if so then it pushes the current status onto the stack and creates a new stack frame to handle the interupt and runs the code.
"Is there any way that Task 2, instead of printing "hello", can forcibly stop Task 1?"
No, not without the cooperation of Task 1.
To elaborate on the background pool Walter mentioned, isn't that an option for your app?
You just invoke the cancel method with your app's red button.
psize = 35; % problem size
tlim = 16; % time limit (s)
fun = @(x) sum(100*(x(2:2:end) - x(1:2:end).^2).^2 + (1 - x(1:2:end)).^2);
x0 = repmat([-1.2, 1], 1, psize);
options = optimset(TolX=1e-10, MaxFunEvals=1e7, MaxIter=5e6);
%{
tic
x = fminsearch(fun,x0,options);
toc
% ~ 10s for psize == 35
%}
bp = backgroundPool;
f = parfeval(bp, @() fminsearch(fun, x0, options), 1);
tic
t = 0;
while t < tlim && strcmpi(f.State, 'running')
pause(1)
t = toc;
disp(t + "s: still running")
end
if ~strcmpi(f.State, 'finished')
cancel(f)
disp(t + "s: canceled")
else
disp(t + "s: finished")
X = fetchOutputs(f);
end
Good point, canceling a parfeval (background pool or Parallel Computing Toolbox pool) is potentially a way of stopping execution without the cooperaration of the thing being executed.
However, it is not clear under what circumstances a cancel takes effect: if the background item is currently calling into compiled libraries, it is not clear that the cancel will take effect "soon" or if it waits until the library call returns.
Okay, but hitting "the red 'stop' square button", as the OP suggests, would have similar limitations (at least), wouldn't it?
Yes, hitting the Stop button has the limitation that it does not stop until the next line of MATLAB code.

Sign in to comment.

Categories

Products

Release

R2023b

Asked:

Ken
on 21 Apr 2024

Commented:

on 23 Apr 2024

Community Treasure Hunt

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

Start Hunting!