§ 3.1.Системаобработкипрерываний
Обладая способностью переключаться от одного потока выполнения к другому,
ядро операционной системы должно к тому же реагировать на прерывания (interrupts) и
исключения (exceptions). Речь идет о сигналах, которые возникают в системе и застав-
ляют процессор прерывать свою работу и переключаться на обработку возникшей си-
туации. Рассмотрим эти два механизма более подробно.
Прерывания представляют собой механизм, позволяющий координировать парал-
лельное функционирование отдельных устройств вычислительной системы и реагиро-
вать на особые состояния, возникающие при работе процессора. Таким образом, преры-
вание-этопринудительнаяпередачауправленияотвыполняемойпрограммык
системе (а через нее - к соответствующей программе обработки прерывания), происхо-
дящая при возникновении определенного события.
Идея прерываний была предложена в середине 50-х годов и можно без преувели-
чения сказать, что она внесла наиболее весомый вклад в развитие вычислительной тех-
ники. Основная цель введения прерываний - реализация асинхронного режима работы и
распараллеливание работы отдельных устройств вычислительного комплекса.
Механизм прерываний реализуется аппаратно-программными средствами. Перво-
начально рассмотрим в общих чертах аппаратную часть системы прерываний. Сигналы
аппаратных прерываний, возникающие в устройствах, входящих в состав компьютера
или подключенных к нему, поступают в процессор не непосредственно, а через два кон-
троллера прерываний, один из которых называется ведущим, а второй ведомым
(рис.3.1). В прежних моделях машин контроллеры представляли собой отдельные мик-
|
росхемы; в современных компьютерах они входят в состав многофункциональной мик-
росхемы периферийного контроллера.
Рис.3.1. Аппаратная часть системы прерываний.
Два контроллера используются для увеличения допустимого числа внешних уст-
ройств. Дело в том, что каждый контроллер прерываний может обслуживать сигналы
лишь от восьми устройств. Для обслуживания большего количества устройств контрол-
леры можно объединять, образуя из них веерообразную структуру. В современных ма-
шинах устанавливают два контроллера, увеличивая тем самым возможное число вход-
ных устройств до 15 (7 у ведущего и 8 у ведомого контроллера).
К входным выводам IRQ1...IRQ7 и IRQ8...IRQ15 (IRQ - это сокращение от Interrupt
Request, запрос прерывания) подключаются выводы устройств, на которых возникают
сигналы прерываний. Выход ведущего контроллера подключается к входу INT микро-
процессора, а выход ведомого - к входу IRQ2 ведущего. Основная функция контролле-
ров - передача сигналов запросов прерываний от внешних устройств на единственный
вход прерываний процессора. При этом, кроме сигнала INT, контроллеры передают в
процессор по линиям данных номер вектора, который образуется в контроллере путем
сложения базового номера, записанного в одном из его регистров, с номером входной
линии, по которой поступил запрос прерывания. Номера базовых векторов заносятся в
контроллеры автоматически в процессе начальной загрузки компьютера. Очевидно, что
номера векторов аппаратных прерываний однозначно связаны с номерами линий, или
|
уровнями IRQ, а через них - с конкретными устройствами компьютера. На рис.3.1 обо-
значены основные устройства компьютера, работающие в режиме прерываний.
Процессор, получив по линии INT сигнал прерывания, выполняет последователь-
ность стандартных действий, которую можно назвать процедурой прерывания. Смысл
процедуры прерывания заключается в том, чтобы сохранить состояние текущей (преры-
ваемой) программы и передать управление обработчику, соответствующему возникше-
му прерыванию.
Структуры систем прерывания (в зависимости от аппаратной архитектуры) могут
быть самыми разными, но все они имеют одну общую особенность - прерывание непре-
менно влечет за собой изменение порядка выполнения команд процессором.
Механизм обработки прерываний независимо от архитектуры вычислительной
системы включает следующие элементы [2]:
1. Установление факта прерывания (прием сигнала на прерывание) и идентифика-
ция прерывания (в операционных системах иногда осуществляется повторно, на
шаге 4).
2. Запоминание состояния прерванного процесса. Состояние процесса определяется
прежде всего значением счетчика команд (адресом следующей команды, кото-
рый, например, в i80x86 определяется регистрами CS и IP - указателем команды),
содержимым регистров процессора и может включать также спецификацию ре-
жима (например, режим пользовательский или привилегированный) и другую
информацию.
3. Управление аппаратно передается подпрограмме обработки прерывания. В про-
стейшем случае в счетчик команд заносится начальный адрес подпрограммы об-
|
работки прерываний, а в соответствующие регистры - информация из слова со-
стояния. В более развитых процессорах, например в том же i80286 и
последующих 32-битовых микропроцессорах, начиная с i80386, осуществляется
достаточно сложная процедура определения начального адреса соответствующей
подпрограммы обработки прерывания и не менее сложная процедура инициали-
зации рабочих регистров процессора.
4. Сохранение информации о прерванной программе, которую не удалось спасти на
шаге 2 с помощью действий аппаратуры. В некоторых вычислительных системах
предусматривается запоминание довольно большого объема информации о со-
стоянии прерванного процесса.
5. Обработка прерывания. Эта работа может быть выполнена той же подпрограм-
мой, которой было передано управление на шаге 3, но в ОС чаще всего она реа-
лизуется путем последующего вызова соответствующей подпрограммы.
6. Восстановление информации, относящейся к прерванному процессу (этап, об-
ратный шагу 4).
7. Возврат в прерванную программу.
Шаги 1-3 реализуются аппаратно, а шаги 4-7 - программно. На рис.3.2 показано,
что при возникновении запроса на прерывание естественный ход вычислений нарушает-
ся и управление передается программе обработки возникшего прерывания. При этом
средствами аппаратуры сохраняется (как правило, с помощью механизмов стековой па-
мяти) адрес той команды, с которой следует продолжить выполнение прерванной про-
граммы. После выполнения программы обработки прерывания управление возвращается
прерванной ранее программе посредством занесения в указатель команд сохраненного
адреса команды. Однако такая схема используется только в самых простых программ-
ных средах. В мультипрограммных операционных системах обработка прерываний про-
исходит по более сложным схемам, о чем будет более подробно написано ниже.
Рис.3.2. Обработка прерывания
Итак, главныефункциимеханизмапрерываний:
• распознавание или классификация прерываний;
• передача управления соответственно обработчику прерываний;
• корректное возвращение к прерванной программе.
Переход от прерываемой программы к обработчику и обратно должен выполняться
как можно быстрей. Одним из быстрых методов является использование таблицы, со-
держащей перечень всех допустимых для компьютера прерываний и адреса соответст-
вующих обработчиков. Для корректного возвращения к прерванной программе перед
передачей управления обработчику прерываний содержимое регистров процессора за-
поминается либо в памяти с прямым доступом, либо в системном стеке - system stack.
Прерывания, возникающие при работе вычислительной системы, можно разделить
на два основных класса: внешние (их иногда называют асинхронными) и внутренние
(синхронные).
Внешниепрерывания вызываются асинхронными событиями, которые происходят
вне прерываемого процесса, например:
• прерывания от таймера;
• прерывания от внешних устройств (прерывания по вводу/выводу);
• прерывания по нарушению питания;
• прерывания с пульта оператора вычислительной системы;
• прерывания от другого процессора или другой вычислительной системы.
Внутренниепрерывания вызываются событиями, которые связаны с работой про-
цессора и являются синхронными с его операциями. Примерами являются следующие
запросы на прерывания:
• при нарушении адресации (в адресной части выполняемой команды указан запре-
щенный или несуществующий адрес, обращение к отсутствующему сегменту или
странице при организации механизмов виртуальной памяти);
• при наличии в поле кода операции незадействованной двоичной комбинации;
• при делении на нуль;
• при переполнении или исчезновении порядка;
• при обнаружении ошибок четности, ошибок в работе различных устройств аппара-
туры средствами контроля.
Могут еще существовать прерывания при обращении к супервизору ОС - в некото-
рых компьютерах часть команд может использовать только ОС, а не пользователи. Со-
ответственно в аппаратуре предусмотрены различные режимы работы, и пользователь-
ские программы выполняются в режиме, в котором эти привилегированные команды не
исполняются. При попытке использовать команду, запрещенную в данном режиме, про-
исходит внутреннее прерывание и управление передается супервизору ОС. К привиле-
гированным командам относятся и команды переключения режима работа центрального
процессора.
Наконец, существуют собственно программныепрерывания. Эти прерывания
происходят по соответствующей команде прерывания, то есть по этой команде процес-
сор осуществляет практически те же действия, что и при обычных внутренних прерыва-
ниях. Данный механизм был специально введен для того, чтобы переключение на сис-
темные программные модули происходило не просто как переход в подпрограмму, а
точно таким же образом, как и обычное прерывание. Этим обеспечивается автоматиче-
ское переключение процессора в привилегированный режим с возможностью исполне-
ния любых команд.
Сигналы, вызывающие прерывания, формируются вне процессора или в самом
процессоре; они могут возникать одновременно. Выбор одного из них для обработки
осуществляется на основе приоритетов, приписанных каждому типу прерывания. Оче-
видно, что прерывания от схем контроля процессора должны обладать наивысшим при-
оритетом (если аппаратура работает неправильно, то не имеет смысла продолжать обра-
ботку информации). На рис.3.3 изображен обычный порядок (приоритеты) обработки
прерываний в зависимости от типа прерываний [2].
Рис.3.3. Распределение прерываний по уровням приоритета
Учет приоритета может быть встроен в технические средства, а также определяться
операционной системой, то есть кроме аппаратно реализованных приоритетов прерыва-
ния большинство вычислительных машин и комплексов допускают программно-
аппаратное управление порядком обработки сигналов прерывания. Второй способ, до-
полняя первый, позволяет применять различные дисциплиныобслуживанияпрерыва-
Ний.
Наличие сигнала прерывания не обязательно должно вызывать прерывание испол-
няющейся программы. Процессор может обладать средствами защиты от прерываний:
отключение системы прерываний, маскирование (запрет) отдельных сигналов прерыва-
ния. Программное управление этими средствами (существуют специальные команда для
управления работой системы прерываний) позволяет операционной системе регулиро-
вать обработку сигналов прерывания, заставляя процессор обрабатывать их сразу по
приходу, откладывать их обработку на некоторое время или полностью игнорировать.
Обычно операция прерывания выполняется только после завершения выполнения теку-
щей команды. Поскольку сигналы прерывания возникают в произвольные моменты вре-
мени, то на момент прерывания может существовать несколько сигналов прерывания,
которые могут быть обработаны только последовательно. Чтобы обработать сигналы
прерывания в разумном порядке им присваиваются приоритеты. Сигнал с более высо-
ким приоритетом обрабатывается в первую очередь, обработка остальных сигналов пре-
рывания откладывается.
Программное управление специальными регистрами маски (маскирование сигна-
лов прерывания) позволяет реализовать различные дисциплины обслуживания [2]:
• с относительнымиприоритетами, то есть обслуживание не прерывается даже
при наличии запросов с более высокими приоритетами. После окончания обслу-
живания данного запроса обслуживается запрос с наивысшим приоритетом. Для
организации такой дисциплины необходимо в программе обслуживания данного
запроса наложить маски на все остальные сигналы прерывания или просто от-
ключить систему прерываний;
• с абсолютнымиприоритетами, то есть всегда обслуживается прерывание с
наивысшим приоритетом. Для реализации этого режима необходимо на время
обработки прерывания замаскировать все запросы с более низким приоритетом.
При этом возможно многоуровневое прерывание, то есть прерывание программ
обработки прерываний. Число уровней прерывания в этом режиме изменяется и
зависит от приоритета запроса;
• по принципустека, или, как иногда говорят, подисциплине LCFS (last come first
served - последним пришел - первым обслужен), то есть запросы с более низким
приоритетом могут прерывать обработку прерывания с более высоким приорите-
том. Дли этого необходимо не накладывать маски ни на один сигнал прерывания
и не выключать систему прерываний.
Следует особо отметить, что для правильной реализации последних двух дисцип-
лин нужно обеспечить полное маскирование системы прерываний при выполнении ша-
гов 1-4 и 6-7. Это необходимо для того, чтобы не потерять запрос и правильно его об-
служить. Многоуровневое прерывание должно происходить на этапе собственно
обработки прерывания, а не на этапе перехода с одного процесса на другой.
Управление ходом выполнения задач со стороны ОС заключается в организации
реакций на прерывания, в организации обмена информацией (данными и программами),
предоставлении необходимых ресурсов, в динамике выполнения задачи и в организации
сервиса. Причины прерываний определяет ОС (модуль, который называют супервизо-
ром прерываний), она же и выполняет действия, необходимые при данном прерывании и
в данной ситуации. Поэтому в состав любой ОС реального времени прежде всего входят
программы управления системой прерываний, контроля состояний задач и событий,
синхронизации задач, средства распределения памяти и управления ею, а уже потом
средства организации данных (с помощью файловых систем и т. д.). Следует, однако,
заметить, что современная ОС реального времени должна вносить в аппаратно-
программный комплекс нечто большее, нежели просто обеспечение быстрой реакции на
прерывания.
Как мы уже знаем, при появлении запроса на прерывание система прерываний
идентифицирует сигнал и, если прерывания разрешены, управление передается на соот-
ветствующую подпрограмму обработки. Из рис.3.2 видно, что в подпрограмме обработ-
ки прерывания имеются двеслужебныесекции. Это - первая секция, в которой осуще-
ствляется сохранение контекста прерванной задачи, который не смог быть сохранен на
2-м шаге, и последняя, заключительная секция, в которой, наоборот, осуществляется
восстановление контекста. Для того чтобы система прерываний не среагировала повтор-
но на сигнал запроса на прерывание, она обычно автоматически «закрывает» (отключа-
ет) прерывания, поэтому необходимо потом в подпрограмме обработки прерываний
вновь включать систему прерываний. Установка рассмотренных режимов обработки
прерываний (с относительными и абсолютными приоритетами, и по правилу LCFS)
осуществляется в конце первой секции подпрограммы обработки. Таким образом, на
время выполнения центральной секции (в случае работы в режимах с абсолютными при-
оритетами и по дисциплине LCFS) прерывания разрешены. На время работы заключи-
тельной секции подпрограммы обработки система прерываний должна быть отключена
и после восстановления контекста вновь включена. Поскольку эти действия необходимо
выполнять практически в каждой подпрограмме обработки прерываний, во многих опе-
рационных системах первые секции подпрограмм обработки прерываний выделяются в
специальный системный программный модуль, называемый супервизоромпрерываний.
Супервизорпрерываний прежде всего сохраняет в дескрипторе текущей задачи
рабочие регистры процессора, определяющие контекст прерываемого вычислительного
процесса. Далее он определяет ту подпрограмму, которая должна выполнить действия,
связанные с обслуживанием настоящего (текущего) запроса на прерывание. Наконец,
перед тем как передать управление этой подпрограмме, супервизор прерываний уста-
навливает необходимый режим обработки прерывания. После выполнения подпрограм-
мы обработки прерывания управление вновь передается супервизору, на этот раз уже на
тот модуль, который занимается диспетчеризацией задач. И уже диспетчер задач, в свою
очередь, в соответствии с принятым режимом распределения процессорного времени
(между выполняющимися процессами) восстановит контекст той задачи, которой будет
решено выделить процессор. Рассмотренная схема проиллюстрирована на рис.3.4 [2].
Как видно из рис.3.4, здесь нет непосредственного возврата в прерванную ранее
программу непосредственно из самой подпрограммы обработки прерывания. Для прямо-
го непосредственного возврата достаточно адрес возврата сохранить в стеке, что и дела-
ет аппаратура процессора. При этом стек легко обеспечивает возможность возврата в
случае вложенных прерываний, поскольку он всегда реализует дисциплину LCFS (last
come - first served).
Однако если бы контекст процессов сохранялся просто в стеке, как это обычно
реализуется аппаратурой, а не в дескрипторах задач, то не было бы возможности гибко
подходить к выбору той задачи, которой нужно передать процессору после завершения
работы подпрограммы обработки прерывания.
Рассмотрим как производится обработка прерываний в ОС Windows [4]. В этой
операционной системе каждому прерыванию назначается определенный приоритет, на-
зываемый уровнемзапросапрерывания (interrupt request level, IRQL). IRQL назначается
источнику прерывания. Например, мышь имеет IRQL, который присваивается посту-
пающим от нее сигналам. Системный таймер также генерирует собственные прерыва-
ния, которым назначается другой IRQL.
Рис.3.4. Обработка прерывания при участии супервизоров ОС
Центральный процессор также имеет свой IRQL, который изменяется по мере ра-
боты системы. Изменение IRQL центрального процессора позволяет системе блокиро-
вать прерывания с более низким приоритетом. Приоритет процессора могут изменить
только системные сервисы, работающие на уровне ядра, например перехватчик. Потоки,
функционирующие на пользовательском уровне, не имеют таких привилегий. Заблоки-
рованным прерываниям внимание не уделяется до тех пор, пока какой-нибудь поток яв-
ным образом не понизит уровень прерывания центрального процессора. Если процессор
работает при самом низком значении IRQL, происходит нормальное выполнение потока
и разрешается обработка всех прерываний. Когда перехватчик вызывает процедуруоб-
служиванияпрерывания (interrupt service routine, ISR), он сначала назначает централь-
ному процессору тот же IRQL, который имеет перехваченный сигнал. На время выпол-
нения ISR прерывания более низкого уровня, например сигналы от устройств ввода
данных, блокируются, чтобы не отвлекать систему от выполнения критических опера-
ций, таких как процедуры восстановления при отключении питания. При понижении
IRQL процессора заблокированные прерывания разблокируются и начинают поочередно
обрабатываться обычным образом. Время от времени центральный процессор переклю-
чается на самый низкий IRQL, чтобы возобновить выполнение прерванных потоков.
Прежде чем приступить к обработке прерывания, перехватчик должен найти в сис-
теме соответствующую подпрограмму. Он ищет такие подпрограммы в таблицерас-
пределенияпрерываний (interrupt dispatch table, IDT). Указанная таблица содержит 32
записи, по одной для каждого уровня запроса прерывания. Каждая из таких записей ука-
зывает на подпрограмму обработки прерывания или на последовательную цепочку таких
подпрограмм - в том случае, если несколько устройств используют один и тот же IRQL.
При загрузке в систему новый драйвер устройства записывает в IDT собственный
обработчик. Драйверы делают это путем создания и подключения объекта-прерывания,
т.е. структуры, содержащей всю информацию, необходимую ядру для дополнения IDT.
С помощью объекта-прерывания драйверы получают возможность зарегистрировать
свои обработчики прерываний, ничего не зная ни об аппаратном устройстве, ни о струк-
туре таблицы распределения прерываний.
§ 3.2.Общиепринципыобработкиисключений
По мере выполнения программы ее нормальная работа по различным причинам
может нарушаться. В частности, это может быть связано с тем, что центральный процес-
сор наталкивается на недопустимый адрес памяти, пользователь прерывает выполнение
программы комбинацией "горячих" клавиш [Ctrl+C], отладчик произвольным образом
останавливает программу и запускает ее вновь; ошибка может быть связана и с вводом
неправильного значения при выполнении операции с плавающей запятой. Эти и другие
исключительные ситуации способны возникать как на пользовательском уровне, так и
на уровне ядра операционной системы, как в RISC-процессорах, так и в процессорах
Intel. О возникновении подобных ситуаций может сигнализировать и аппаратное, и про-
граммное обеспечение. Любой язык программирования должен содержать средства об-
работки исключений для унификации процесса обработки, выполняемой в различных
ситуациях. Windows включает встроенные низкоуровневые механизмы структурирован-
ной обработки исключений [12].
Исключения в значительной степени аналогичны прерываниям. В первую очередь
тем, что оба сигнала заставляют центральный процессор передать управление специаль-
ной части операционной системы. Однако исключения и прерывания - это не одно и то
же. Прерывания происходят асинхронно, часто в результате определенных аппаратных
событий, например нажатий клавиш или поступления данных через последовательный
порт. Программа не имеет возможности контролировать такие прерывания, и они могут
происходить в любой момент. С другой стороны, исключения возникают синхронно, как
результат выполнения определенных операторов программы. Исключения часто служат
сигналом, свидетельствующим о наличии ошибочных условий. Обычно они воспроиз-
водятся путем повторного запуска программы с тем же контекстом.
Исключения часто генерируются в том случае, если какая-то часть программы об-
наруживает ошибку, но не может обработать ее самостоятельно. Так, система генериру-
ет исключение в ответ на ошибки доступа к памяти и ошибки типа деления на ноль. Од-
нако не все исключения порождаются ошибочными ситуациями. Windows генерирует
специальное исключение для вызова определенного системного сервиса. При обработке
этого исключения ядро передает управление той части операционной системы, которая
предоставляет запрашиваемый сервис.
Любое порожденное исключение должно быть обработано если не самой програм-
мой, то операционной системой, а точнее, должна откликнуться определенная подпро-
грамма, которая обработает и снимет исключение. Следовательно, обработка исключе-
ний заключается в создании специальных блоков программного кода, которые
запускаются при возникновении исключительных ситуаций. Каждое приложение долж-
но содержать несколько маленьких обработчиков, защищающих различные части про-
граммы от всевозможных исключений.
В процессе поиска соответствующего блока программного кода, предназначенного
для конкретной исключительной ситуации, система сначала просматривает текущую
процедуру, затем возвращается назад по стеку вызовов, просматривает другие активные
отложенные процедуры того же процесса и, наконец, переходит к системным обработ-
чикам исключений. Если процесс, породивший исключение, находится под защитой от-
ладчика, последний также получает шанс обработать исключение.
Средства обработки ошибок в различных подсистемах и языках программирования
несколько отличаются друг от друга. Например, WOW-подсистема (Windows on Win32 -
защищенная подсистема, выполняющаяся внутри процесса виртуальной DOS-машины)
должна обрабатывать все исключения непосредственно, поскольку клиенты Winl6 не
имеют возможности делать это самостоятельно. Кроме того, в различных языках про-
граммирования может сильно различаться синтаксис операторов обработки исключений.
Термин структурированнаяобработкаисключений подразумевает, что язык содержит
определенную управляющую структуру, связанную с исключениями.
Программисты, впервые столкнувшиеся с проблемой структурированной обработ-
ки исключений, часто ошибочно полагают, что больше нет необходимости проверять
код завершения каждой команды. На самом деле, ошибка - это далеко не то же самое,
что исключение. Функция может завершиться без генерации исключения. Рассмотрим в
качестве примера следующие строки программного кода, реализованного на API-
функциях для ОС Windows:
hBrush = CreateSolidBrush(RGB(255, 0, 0));
hOldBrush = SelectObject(hDC, hBrush);
Rectangle (hDC, 0, 0, 100, 100);
Если первая команда выполняется некорректно и возвращает для создаваемой кис-
ти значение NULL, то функция SelectObject() также не может быть выполнена. Третья
команда все же рисует прямоугольник, однако закрашивает его не тем цветом, который
нужен. Исключения при этом не генерируются. Единственный способ защиты от подоб-
ных ошибок заключается в проверке возвращаемого значения. Вот еще один пример:
HANDLE hMemory;
char *pData;
hMemory =GlobalAlloc(GHND, 1000);
pData = (char *)GlobalLock(hMemory);
В случае возникновения ошибки, связанной с выделением памяти, переменная
hMemory принимает значение NULL, функция GlobalLock() не выполняется и перемен-
ная pData также получает значение NULL. Однако ни одна из этих ошибок не порождает
исключения. Но следующая строка программного кода при попытке произвести запись
по неправильному адресу генерирует исключение:
pData[0] = "а";
// порождает исключение, если pData = NULL
Исключение представляет собой разновидность ошибки, которая не может быть
обработана самой командой. Если функция GlobalAlloc не обнаруживает достаточно
места, для своего выполнения, она просто возвращает значение NULL. Но если операто-
ру присваивания некуда передавать значение, он не выполняет никаких действий и даже
не возвращает код ошибки. При этом порождается исключение, и если процесс не может
его обработать, операционная система должна закрыть данный процесс.
Часто бывает трудно провести черту между ошибками и исключениями. Различие
между ними порой зависит от конкретной реализации. Для того чтобы распознавать ко-
манды, которые могут порождать исключения, необходимо иметь некоторый опыт. Вы
должны знать всевозможные типы исключений и быть в состоянии определить, какие
операции могут их породить. Например, ошибка в операторе присваивания приводит к
исключению типа нарушениеправдоступа. Список возможных исключений обычно
изменяется в зависимости от конкретною компьютера, однако имеется ряд исключений,
которые определяются на уровне ядра Windows [12]:
• несоответствие типов данных (data-type misalignment);
• прерывание отладчика (debugger breakpoint);
• пошаговая отладка (debugger single-step);
• деление на ноль в операции с плавающей запятой (floating-point divide by zero);
• переполнение и потеря разрядов в операции с плавающей запятой (floating-point
overflow and underflow);
• зарезервированный операнд в операции с плавающей запятой (floating-point reserved
operand);
• нарушение защиты страницы (guard-page violation);
• недопустимый оператор (illegal instruction);
• деление на ноль в операции с целыми числами (integer divide by zero);
• переполнение в операции с целыми числами (integer overflow);
• нарушение прав доступа к памяти (memory-access violation);
• ошибка чтения страницы (page-read error);
• превышение квоты страничного файла (paging file quota exceeded);
• привилегированный оператор (privileged instruction).
Тип возникшего исключения можно определить, используя функцию DWORD Ge-
tExceptionCode(void). Функция возвращает код исключения. В таблице 3.1 приведены
наименования основных кодов.
Таблица 3.1
EXCEPTION_ACCESS_VIOLATION
EXCEPTION_FLT_DIVIDE_BY_ZERO
EXCEPTION_INT_DIVIDE_BY_ZERO
EXCEPTION_INT_OVERFLOW
EXCEPTION_PRIV_INSTRUCTION
Попытка обращения к ячейке памяти,
доступ к которой запрещен (например,
память не выделена)
Деление на ноль с плавающей точкой
Деление на ноль с фиксированной точкой
Целочисленное переполнение
Попытка исполнения привилегированной
команды
§ 3.3.Средстваобработкиисключенийв Visual C++
Блок программного кода на языке С++ всегда должен начинаться ключевыми сло-
вами try и catch. Блок try помечает фрагмент программы, который может породить ис-
ключение, а блок catch содержит программу, запускающуюся при наличии исключения.
С точки зрения программиста, подобные синтаксические структуры удобны для отделе-
ния программного кода, предназначенного для обработки исключительных ситуаций, от
кода, выполняющего обычные задачи. В Visual C++ реализован механизм обработки
исключений, который основан на схеме, предложенной ANSI-комитетом по стандарти-
зации языка C++. В соответствии с этой схемой, перед вызовом функции, которая может
стать причиной возникновения исключительной ситуации, должен быть инициирован
обработчик исключений. Если функция приводит к возникновению ненормальной си-
туации, генерируется исключение и управление передается обработчику.
В среде Visual C++ обработка исключений поддерживается с помощью нескольких
механизмов:
• функций, обеспечивающих структурированную обработку исключений;
• классов, отвечающих за обработку определенных типов исключений;
• макрокоманд, позволяющих осуществить структуризацию обработчиков исключений
приложения;
• функций, предназначенных для генерации исключений различных типов.
Все эти механизмы позволяют генерировать исключения нужных типов и при не-
обходимости прекращать выполнение программы.
Как уже было сказано выше, основу любого механизма обработки исключений в
среде Visual C++ составляют операторы try и catch. Структура try/catch отделяет подпро-