我在 MATLAB R2013a 中遇到了以下问题,出于某种我不明白的原因,当在函数中定义了计时器(包括 TimerFcn)时,它不会调用 onCleanup 函数。
我添加了两个显示问题的最小示例:
首先是按预期调用清理例程的工作版本:
function mytest(time)
t = timer();
myclean = onCleanup(@() disp('function ended'));
pause(time);
end
现在是不调用清理的错误版本(无论是在函数正常结束时还是在按下 ctrl+c 时)
function mytest2(time)
t = timer();
t.TimerFcn = @(o,s)disp(' ... waiting for some time');
myclean = onCleanup(@() disp('function ends'));
pause(time);
end
我在文档中找不到任何提示,为什么定时器或更具体的 TimerFcn 定义会改变清理代码的执行?
最佳答案
哎呀 - 这太讨厌了。它不是错误,但它肯定不是您从文档中期望的,也不是您想要的。幸运的是,它很容易变通。
首先,发生了什么?
好吧,onCleanup
返回一个 onCleanup 对象。这是一个对象,其唯一目的是将析构函数方法设置为您的 @() disp('function ends')
。当对象超出范围时(您希望它位于函数 mytest2
的末尾),它会被删除,它的析构函数方法会执行,并且您的消息会显示出来。我认为这就是您所期望的。
但是当你创建匿名函数@(o,s)disp(' ... waiting for some time')
,并将其赋值给的TimerFcn
你的计时器,它需要函数 mytest2
的整个当前工作区的副本,包括 onCleanup
对象。计时器是在基础工作区(而不是函数工作区)中创建的,并且即使在函数结束时仍然存在,以及 onCleanup
对象,它永远不会超出范围,永远不会获取已删除,其析构函数永远不会运行,您也不会收到消息。
注意:
- 如果你运行
a = timerfindall; delete(a);
在基础工作区中,您将收到消息,因为您已经明确删除了计时器以及onCleanup
对象。 - 这种关于匿名函数获取其整个工作区的副本的行为已被完整记录,尽管您可能没有意识到,并且您显然不希望它在这里这样工作。这很讨厌。
幸运的是,它很容易变通:
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
现在,当创建匿名函数时,它只获取其本地 工作区的副本(即来自子函数 setTimerFcn
),其中不包括 onCleanup
对象。 onCleanup
对象超出您预期的范围,一切正常。
希望对您有所帮助!
关于Matlab onCleanup 函数未执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22898001/