вторник, 24 апреля 2012 г.

MATLAB: как правильно перехватить Ctrl+C

При долгих вычислениях иногда необходимо прекратить выполнение программы. Сделать это можно нажатием клавиш Ctrl+C в главном окне MATLAB.

Например, имеется функция, которая очевидно никогда не завершит своё выполнение:
function slow_function
 i = 1;
 while true
  i = i + 1;
 end
end

Запустив её, единственным способом прервать вычисления, как указывалось выше, является комбинация клавиш Ctrl+C, нажав которую MATLAB прекратить вычисления и покажет сообщение об ошибке:
>> slow_function
Operation terminated by user during slow_function (line 5)

В данном случае прерывание выполнения не приведёт ни к чему плохому. Однако в некоторых случаях требуется выполнять дополнительные действия (освобождать память, закрывать файлы, показывать на графике текущие результаты и т.д.).


К сожалению (а может к счастью) исключительная ситуация не возбуждается. Поэтому в следующем примере по нажатию на Ctrl+C не будет выведено сообщение:
function slow_function
 i = 1;
 try
  while true
   i = i + 1;
  end
 catch
  disp('Опа!')
 end
end

>> slow_function
Operation terminated by user during slow_function (line 6)


Единственным и правильным решением будет использование функции onCleanup:
function slow_function
 i = 1;
 cleanupObj = onCleanup( @() disp('Опа!') );
 while true
  i = i + 1;
 end
end

>> slow_function
Опа!
Operation terminated by user during slow_function (line 6)

Здесь используется механизм анонимных функций. Пара полезных примеров есть в документации по функции (на самом деле классу) onCleanup. В конце работы функции slow_function будет вызвана анонимная функция, которая выполняет необходимые действия.

Идея в основе класса (именно класса!) onCleanup проста - создать объект, проинициализировать его дескриптором на анонимную функцию, а в деструкторе вызвать эту анонимную функцию.

Может возникнуть ложное впечатление, что код:
function slow_function
 if true
  cleanupObj = onCleanup( @() disp('Опа!') );
 end
 disp('Сообщение');
end
сперва выведет "Опа", а затем "Сообщение!", поскольку cleanupObj выйдет из области видимости условного оператора.

Однако в MATLAB область видимости определяется по другому, чем в C и подобных ему языках: удаление переменных происходит по завершению функции или по выполнению функции clear. А вот код:
function slow_function
 if true
  cleanupObj = onCleanup( @() disp('Опа!') );
  clear cleanupObj;
 end
 disp('Сообщение');
end
действительно выведет сперва "Опа", а затем "Сообщение!".

Просто ещё раз впечатляет архитектура и мощь объектно-ориентированного программирования в MATLAB.

Комментариев нет:

Отправить комментарий