- •Раздел 2. Механизмы последовательного выполнения программ
- •2.1. Классификация методов замены контекста
- •2.2. Процедуры как синхронные методы замены контекста
- •2.3. Сопрограммы
- •2.4. Примеры реализации сопрограмм в Си, в защищенном режиме процессора и в Windows
- •2.4.1. Пример реализации сопрограмм в Си
- •2.4.2. Пример реализации сопрограмм в защищенном режиме
- •2.4.3. Пример реализации сопрограмм средствами Windows api
- •2.4.4. Пример реализации сопрограмм средствами ос Linux
- •2.5. Процедуры ос
- •2.6. Прерывания как асинхронный метод замены контекста
- •2.7. Исключения
- •2.7.1. Самая общая характеристика исключений
- •2.7.2 Исключения на низком уровне
- •2.7.3. Исключения в программных средах
2.7.3. Исключения в программных средах
Важно отметить, что речь далее пойдет только о тех исключительных ситуациях, которые программист знает, как исправить. Если программист не знает, как исправить исключительную ситуацию (это, как правило, относится к исключениям типа GPF и ко всем исключениям низкого уровня, кроме деления на ноль), то обработку этого исключения необходимо оставить системе.
Кроме того, речь здесь пойдет о новой (относительно) концепции обработки чисто программных ошибок - обработке на уровне исключений, когда о наличии ошибки программа сигнализирует исключительной ситуацией, что повышает наглядность и структурированность программы.
Для того чтобы программа могла создавать исключительные ситуации и уметь их обрабатывать система программирования должна обладать специальными средствами, о которых речь пойдет ниже.
Такими средствами обладают языки Ада, Си++, среда Delphi, Java.
Дадим общую характеристику исключений с точки зрения языка высокого уровня.
При возникновении исключения нормальное выполнение программы прекращается и инициируется работа обработчика исключения. После завершения обработки исключения выполнение программы не возобновляется в точке возникновения исключения. Процесс установления связи между конкретной ошибочной ситуацией и соответствующим обработчиком называется возбуждением исключения. При возбуждении операторы, описанные в обработчике, выполняются. Сам обработчик исключений помещается в конце блока программы. Если в данном блоке не описан обработчик исключительной ситуации, то обработка исключения передается в блок, внешний по отношению к тому блоку, в котором возбуждено исключение, и т.д. Такая передача исключения называется распространением исключения. Если и в самом внешнем блоке программы отсутствует обработчик, то обработка исключения передается среде и выполнение программы в этом случае аварийно завершается.
Традиционно для проверки наличия ошибочной ситуации используются явные проверки, которые загромождают программу.
Приведем пример работы с файлом. Последовательность работы с файлом выглядит следующим образом:
void FileWork()
{
open(…);//Открыть файл;
read(…);//Прочитать данные из файла;
write(…);//Записать данные в файл;
close(…);//Закрыть файл;
}
На каждом шаге может возникнуть ошибка ввода-вывода, приводящая к аварийному завершению программы. Например, файл отсутствует или читаем данные за концом файла.
Чтобы программа не завершалась аварийно, надо после каждой операции проверять результат выполнения операции:
void FileWork()
{
int rc = open(…);
if (rc == -1) {
perror(“open:”);
exit(0);
}
rc = read(…);
if (rc == -1) {
perror(“read:”);
exit(0);
}
rc = write(…);
if (rc == -1) {
perror(“write:”);
exit(0);
}
rc = close(…);
if (rc == -1) {
perror(“close:”);
exit(0);
}
}
После каждой операции ввода-вывода необходимо делать явные проверки. Если таких операций много, то громоздкость программы становится очевидной и наглядность резко снижена.
Обработчик исключений позволяет отделить операторы работы с файлом от операторов проверки ошибочной ситуации и скомпоновать проверки в отдельной части программы, не перемежая их с операторами, в которых могут возникать ошибки. В общем виде это будет выглядеть для нашего примера следующим образом:
void FileWork()
{
try{
open(…);
read(…);
write(…);
close(…);
}catch(…){
Операторы обработки исключения, например, сообщение пользователю об ошибке;
}
}
Впервые подобный способ обработки ошибочных ситуаций был предложен в языке высокого уровня Ада и далее был распространен на более широко используемые языки.
Заключение по разделу 2
Еще раз сопоставим все пять перечисленных методов замены контекста.
Процедуры - самый простой способ замены контекста на основе одного стека.
Сопрограммы - отличаются от процедур наличием собственных стеков каждая.
Процедуры ОС выполняют еще более глубокую замену контекста с включением проверки прав пользователя на этот вызов.
Прерывания - это асинхронный способ замены контекста, обусловленный внешней по отношению к процессору причиной, с необязательным возвратом в прерванную программу.
Исключения - это также асинхронный способ замены контекста, но обусловленный внутренними причинами - ошибками в ходе выполнения операций программы.