Matlab onCleanup函数未执行

use*_*203 5 matlab

我在MATLAB R2013a中遇到了以下问题,由于某些原因我不明白在函数中定义了一个定时器(包括TimerFcn)时没有调用onCleanup函数.

我添加了两个显示问题的最小示例:

首先是按预期调用清理例程的工作版本:

function mytest(time)
  t = timer();
  myclean = onCleanup(@() disp('function ended'));
  pause(time);
end
Run Code Online (Sandbox Code Playgroud)

现在是没有调用清理的错误版本(当函数正常结束或按下ctrl + c时)

function mytest2(time)
  t = timer();
  t.TimerFcn = @(o,s)disp(' ... waiting for some time'); 
  myclean = onCleanup(@() disp('function ends'));
  pause(time);
end
Run Code Online (Sandbox Code Playgroud)

我在文档中找不到任何提示,为什么定时器或更具体的TimerFcn定义会改变清理代码的执行?

Sam*_*rts 5

哎哟 - 这很讨厌.这不是一个错误,但它肯定不是你对文档的期望,它不是你想要的.幸运的是,它很容易解决.

首先,发生了什么?

好吧,onCleanup返回一个onCleanup对象.这是一个对象,其唯一目的是为您设置一个析构函数方法@() disp('function ends').当对象超出范围(您希望在函数末尾mytest2)时,它将被删除,执行析构函数方法,并显示您的消息.我想这就是你所期望的.

但是当您创建匿名函数@(o,s)disp(' ... waiting for some time')并将其分配给TimerFcn计时器时,它会获取函数的整个当前工作空间的副本mytest2,包括onCleanup对象.计时器是在基础工作区(而不是函数工作区)中创建的,并且即使在函数结束时仍然存在,并且onCleanup对象随后永远不会超出范围,永远不会被删除,它的析构函数永远不会运行,而且你没有收到你的消息.

注意:

  1. 如果您a = timerfindall; delete(a);在基础工作区中运行,您将收到消息,因为您已明确删除计时器以及onCleanup对象.
  2. 关于匿名函数获取整个工作区副本的这种行为已经完整记录,尽管您可能没有意识到这一点,尽管您显然不希望它像这样工作.这很讨厌.

幸运的是,它很容易解决:

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
Run Code Online (Sandbox Code Playgroud)

现在,当创建匿名函数时,它只获取其本地工作空间(即来自子函数setTimerFcn)的副本,该副本不包括该onCleanup对象.该onCleanup对象超出范围在你期望的点,一切都很好.

希望有所帮助!