exponenta event banner

Очистка по завершении функций

Обзор

Оптимальная практика программирования заключается в том, чтобы убедиться, что вы оставляете свою программную среду в чистом состоянии, которое не мешает какому-либо другому программному коду. Например, может потребоваться

  • Закройте все файлы, открытые для импорта или экспорта.

  • Восстановите путь MATLAB ®.

  • Заблокируйте или разблокируйте память, чтобы предотвратить или разрешить удаление функции MATLAB или MEX-файлов.

  • Установите для рабочей папки значение по умолчанию, если она была изменена.

  • Убедитесь, что глобальные и постоянные переменные находятся в правильном состоянии.

MATLAB обеспечивает onCleanup функция для этой цели. Эта функция при использовании в любой программе устанавливает подпрограмму очистки для этой функции. Когда функция завершается, как обычно, так и в случае ошибки или Ctrl + C, MATLAB автоматически выполняет процедуру очистки.

Следующая инструкция устанавливает подпрограмму очистки cleanupFun для текущей выполняемой программы:

cleanupObj = onCleanup(@cleanupFun);

Когда программа завершает работу, MATLAB находит любые экземпляры onCleanup и выполняет связанные дескрипторы функций. Процесс создания и активации очистки функции включает в себя следующие шаги:

  1. Запишите одну или несколько подпрограмм очистки для разрабатываемой программы. Предположим, что на данный момент требуется только одна такая процедура.

  2. Создайте дескриптор функции для подпрограммы очистки.

  3. В какой-то момент, обычно на ранней стадии кода программы, вставьте вызов onCleanup функция, передавая дескриптор функции.

  4. При запуске программы вызов onCleanup создает объект подчистки, содержащий дескриптор подпрограммы подчистки, созданной на шаге 1.

  5. По завершении программы MATLAB неявно очищает все объекты, являющиеся локальными переменными. При этом вызывается метод деструктора для каждого локального объекта в программе, включая объект очистки, созданный на шаге 4.

  6. Метод деструктора для этого объекта вызывает эту подпрограмму, если она существует. При этом выполняются задачи, необходимые для восстановления среды программирования.

Для файла программы можно объявить любое количество подпрограмм очистки. Каждый вызов для onCleanup устанавливает отдельную подпрограмму очистки для каждого возвращаемого объекта очистки.

Если по какой-либо причине объект возвращен onCleanup сохраняется после завершения срока действия программы, после чего подпрограмма очистки, связанная с этим объектом, не выполняется после завершения функции. Вместо этого он будет выполняться каждый раз, когда объект уничтожается (например, путем очистки переменной объекта).

Процедура очистки не должна полагаться на переменные, определенные вне этой процедуры. Например, вложенная функция, показанная здесь слева, выполняется без ошибок, в то время как очень похожая функция справа терпит неудачу с ошибкой, Undefined function or variable 'k'. Это является результатом зависимости подпрограммы очистки от переменной k которая определяется вне вложенной подпрограммы очистки:

function testCleanup               function testCleanup
k = 3;                             k = 3;
myFun                              obj = onCleanup(@myFun);
    function myFun                     function myFun
    fprintf('k is %d\n', k)            fprintf('k is %d\n', k)
    end                                end
end                                end

Примеры очистки программы при выходе

Пример 1 - Закрыть открытые файлы при выходе

MATLAB закрывает файл с идентификатором fid когда функция openFileSafely завершает:

function openFileSafely(fileName)
fid = fopen(fileName, 'r');
c = onCleanup(@()fclose(fid));

s = fread(fid);
     .
     .
     .
end

Пример 2 - Ведение выбранной папки

В этом примере сохраняется текущая папка: functionThatMayError возвращает ошибку или нет:

function changeFolderSafely(fileName)
   currentFolder = pwd;
   c = onCleanup(@()cd(currentFolder));

   functionThatMayError;
   end   % c executes cd(currentFolder) here.

Пример 3 - Закрыть рисунок и восстановить путь MATLAB

Этот пример расширяет путь MATLAB, чтобы включить файлы в папки панели инструментов\изображений, а затем отображает рисунок из одной из этих папок. После отображения рисунка выполняется процедура очистки restore_env закрывает фигуру и восстанавливает путь в исходное состояние.

function showImageOutsidePath(imageFile)
fig1 = figure;
imgpath = genpath([matlabroot '\toolbox\images']);

% Define the cleanup routine.
cleanupObj = onCleanup(@()restore_env(fig1, imgpath));

% Modify the path to gain access to the image file, 
% and display the image.
addpath(imgpath);
rgb = imread(imageFile);
fprintf('\n   Opening the figure %s\n', imageFile);
image(rgb);
pause(2);

   % This is the cleanup routine.
   function restore_env(fighandle, newpath)
   disp '   Closing the figure'
   close(fighandle);
   pause(2)
   
   disp '   Restoring the path'
   rmpath(newpath);
   end
end

Запустите функцию, как показано здесь. Можно проверить, восстановлен ли путь, сравнивая длину пути до и после выполнения функции:

origLen = length(path);

showImageOutsidePath('greens.jpg')
   Opening the figure greens.jpg
   Closing the figure
   Restoring the path

currLen = length(path);
currLen == origLen
ans =
     1

Получение информации о подпрограмме очистки

В примере 3, показанном выше, подпрограмма очистки и данные, необходимые для ее вызова, содержатся в дескрипторе анонимной функции:

@()restore_env(fig1, imgpath)

Подробные данные этого дескриптора затем содержатся в объекте, возвращенном onCleanup функция:

cleanupObj = onCleanup(@()restore_env(fig1, imgpath));

Вы можете получить доступ к этим сведениям с помощью task свойства объекта подчистки, как показано здесь. (Изменить showImageOutsidePath добавьте следующий код непосредственно перед строкой комментария ",% This is the cleanup routine.”)

disp '   Displaying information from the function handle:'
task = cleanupObj.task;
fun = functions(task)
wsp = fun.workspace{2,1}
fprintf('\n');
pause(2);

Выполните измененную функцию для просмотра выходных данных functions и содержимое одной из workspace ячейки:

showImageOutsidePath('greens.jpg')

Opening the figure greens.jpg
Displaying information from the function handle:
fun = 
     function: '@()restore_env(fig1,imgpath)'
         type: 'anonymous'
         file: 'c:\work\g6.m'
    workspace: {2x1 cell}
wsp = 
     imageFile: 'greens.jpg'
          fig1: 1
       imgpath: [1x3957 char]
    cleanupObj: [1x1 onCleanup]
           rgb: [300x500x3 uint8]
          task: @()restore_env(fig1,imgpath)

Closing the figure
Restoring the path

Использование onCleanup против try/catch

Другим способом запуска подпрограммы очистки при неожиданном завершении функции является использование try, catch заявление. Однако использование этого метода ограничено. Если пользователь завершает программу, вводя Ctrl + C, MATLAB немедленно выходит из try блок, и подпрограмма очистки никогда не выполняется. Процедура очистки также не выполняется при обычном выходе из функции.

Следующая программа очищается при возникновении ошибки, но не в ответ на Ctrl + C:

function cleanupByCatch
try
    pause(10);
catch
    disp('   Collecting information about the error')
    disp('   Executing cleanup tasks')
end

В отличие от try/catch заявление, onCleanup функция реагирует не только на обычный выход из программы и любую ошибку, которая может быть вызвана, но и на Ctrl + C. Следующий пример заменяет try/catch с onCleanup:

function cleanupByFunc
obj = onCleanup(@()...
    disp('   Executing cleanup tasks'));
pause(10);

onCleanup в сценариях

onCleanup не работает в сценариях, как в функциях. В функциях объект очистки сохраняется в рабочей области функции. При выходе из функции эта рабочая область очищается и выполняется соответствующая процедура очистки. В сценариях объект очистки хранится в базовой рабочей области (то есть рабочей области, используемой в интерактивной работе, выполняемой в командной строке). Поскольку выход из сценария не влияет на базовую рабочую область, объект очистки не очищается, а подпрограмма, связанная с этим объектом, не выполняется. Чтобы использовать этот тип механизма очистки в сценарии, необходимо явным образом очистить объект из командной строки или другого сценария при завершении первого сценария.