Matlab onCleanup function not executed

后端 未结 2 1994
爱一瞬间的悲伤
爱一瞬间的悲伤 2021-01-13 08:09

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 Timer

相关标签:
2条回答
  • 2021-01-13 08:47

    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:

    1. If you run 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.
    2. This behaviour about anonymous functions taking a copy of their entire workspace is fully documented, although you may not be aware of it, and although you clearly don't want it to work like that here. It's nasty.

    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!

    0 讨论(0)
  • 2021-01-13 08:56

    a possible workaround (found by a colleague of me) is to move to definition of the timer into a own function. It is not clear to us why this works but it seems that the definition of a timer in matlab changes the context of some local variables of the function which are not 'deleted' after the function ends as it would be expected from the matlab documentation (Object Life cycle of variables in Matlab)

    A working example is shown below (it uses the defined timer to print simple status messages while waiting) and upon Ctrl+c or when the function ends the Timer is stopped. It furthermore makes sure that only one timer with the name 'timer-mywait' is defined.

    function mytest3(time)
    % register Cleanup handler
    c = onCleanup(@()onCleanup_fcn);
    
    t = mywait_timer(time);
    wait(t);
    
    % onCleanup handle function
    function onCleanup_fcn
        tm = timerfind('Name','timer-mywait');
        if ~isempty(tm) && any(strcmpi(get(tm,'running'),'on'))
        disp('Stopped running timer ''timer-mywait''!');
        stop(tm); 
        end
    end % onCleanup_fcn
    end %mytest3
    
    function t = mywait_timer(time)
        N = 5;    
        t = timerfind('Name','timer-mywait');
        if isempty(t) % avoid multiple definitions of the same timer
        t = timer();
        end
        t.ExecutionMode = 'fixedRate';
        t.TasksToExecute = N+1;
        t.Period = str2num(sprintf('%.3f',time/N)); % Matlab complains about more digits!
        t.Name = 'timer-mywait';
        t.TimerFcn = @(o,s)mywait_timercb();
        start(t),
    end % mywait_timer
    
    function mywait_timercb()
    disp(' still waiting ... ');
    end % mywait_timercb
    
    0 讨论(0)
提交回复
热议问题