I ran into the following issue in MATLAB R2013a, which for some reason I do not understand does not call the onCleanup function when in a function a timer (including a TimerFcn) is defined.
I add two minimal examples showing the problem:
first the working version where the cleanup routine is called as expected:
function mytest(time)
t = timer();
myclean = onCleanup(@() disp('function ended'));
pause(time);
end
and now the buggy version in which the cleanup is not called (neither when the function ends normally or when ctrl+c is pressed)
function mytest2(time)
t = timer();
t.TimerFcn = @(o,s)disp(' ... waiting for some time');
myclean = onCleanup(@() disp('function ends'));
pause(time);
end
I could not find any hints in documentation why the timer or more specific the definition of the TimerFcn would change the execution of the cleanup code?
Ouch - this is nasty. It's not a bug, but it's certainly not what you'd expect from the documentation, and it's not what you'd want. Fortunately it's pretty easy to work around.
Firstly, what's happening?
Well, onCleanup
returns you an onCleanup object. This is an object whose sole purpose is to have a destructor method that is set to your @() disp('function ends')
. When the object goes out of scope (which you would expect to be at the end of the function mytest2
), it gets deleted, its destructor method executes, and your message gets displayed. That's what you expect, I think.
But when you create the anonymous function @(o,s)disp(' ... waiting for some time')
, and assign it to the TimerFcn
of your timer, it takes a copy of the entire current workspace of the function mytest2
, including the onCleanup
object. The timer is created in the base workspace (not the function workspace), and remains in existence even at the end of the function, along with the onCleanup
object, which then never goes out of scope, never gets deleted, its destructor function never runs, and you don't get your message.
Note that:
a = timerfindall; delete(a);
in the base workspace, you will get your message, as you've explicitly deleted the timer along with the onCleanup
object.Fortunately, it's easy to work around:
function mytest3(time)
t = timer();
setTimerFcn(t)
myclean = onCleanup(@() disp('function ends'));
pause(time);
end
function setTimerFcn(t)
t.TimerFcn = @(o,s)disp(' ... waiting for some time');
end
Now, when the anonymous function is created it only takes a copy of its local workspace (i.e. from the subfunction setTimerFcn
), which does not include the onCleanup
object. The onCleanup
object goes out of scope at the point you expect it to, and everything's fine.
Hope that helps!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With