где тело программы
"Декодировать запрос пользователя"
"Выполнить команду, реализующую запрос"
Инструкция
Будем исходить из того, что не все эти программы являются безопасными. Некоторые из них могут отказать в непредсказуемое время. Вы можете обеспечить примитивную, но эффективную защиту против таких событий, написав программу следующим образом:
execute_one_command is
-- Получить запрос от пользователя и, если возможно,
-- выполнить соответствующую команду.
do
"Декодировать запрос пользователя"
"Выполнить подходящую команду в ответ на запрос"
rescue
message ("Извините, эта команда отказала")
message ("Пожалуйста, попробуйте использовать другую команду")
message ("Пожалуйста, сообщите об отказе автору")
"Команды, латающие состояние редактора"
retry
end
Эта схема предполагает на практике, что поддерживаемые запросы пользователя включают:
N-версионное программирование
Другим примером повторения программы, толерантной к неисправностям, является реализация N-версионного программирования - подхода, улучшающего надежность ПО.
В основе N-версионного программирования лежит идея избыточности, доказавшая свою полезность в аппаратуре. В критически важных областях зачастую применяется дублирование аппаратуры, например, несколько компьютеров выполняют одни и те же вычисления, и есть компьютер-арбитр, сравнивающий результаты, и принимающий окончательное решение, если большинство компьютеров дало одинаковый результат. Этот подход хорошо защищает от случайных отказов в аппаратуре отдельного устройства. Он широко применяется в аэрокосмической области. (Известен случай, когда при запуске космического челнока сбой произошел в компьютере-арбитре). N-версионное программирование переносит этот подход на разработку ПО в критически важных областях. В этом случае создаются несколько программистских команд, каждая из которых независимо разрабатывает свою версию системы (программы). Предполагается, что ошибки, если они есть, будут у каждой команды свои.
Это спорная идея; возможно, лучше вложить средства в одну версию, добиваясь ее корректности, чем финансировать две или три несовершенных реализации. Проигнорируем, однако, эти возражения, пусть о полезности идеи судят другие. Нас будет интересовать возможность использования механизма
do_task is
-- Решить проблему, применяя одну из нескольких возможных реализаций.
require
...
local
attempts: INTEGER
do
if attempts = 0 then
implementation_1
elseif attempts = 1 then
implementation_2
end
ensure
...
rescue
attempts := attempts + 1
if attempts < 2 then
"Инструкции, восстанавливающие стабильное состояние"
retry
end
end
Обобщение на большее, чем две, число реализаций очевидно.
Этот пример демонстрирует типичное использование retry. Предложение rescue никогда не пытается достигнуть исходной цели, запуская, например, очередную реализацию. Достижение цели - привилегия нормального тела программы.
Заметьте, после двух попыток (в общем случае
Давайте рассмотрим более тщательно, что случается, когда включается исключение во время выполнения