Т. Пратт, М. Зелковиц - Языки программирования - разработка и реализация (4-е издание_ 2002) (1160801), страница 134
Текст из файла (страница 134)
Реализация Исключительные ситуации могут иметь два различных источника: 1) условия, обнаруженные виртуальной машиной; 2) условия, сгенерированные семантикой языка программирования. В первол1 случае исключения операционной системы могут быть порождены непосредственно аппаратными прерываниями, например арифметическим переполнением, либо они могут быть обусловлены вспомогательным программным обеспечением, наприл|ер условием достижения конца файла.
В С программист имеет прямой доступ к этим сигналам, обрабатываемым операционной системой. Программист может разрешить прерывание (например, при помощи функции з1дасг1оп в П!ч1Х, которая определяет процедуру, вызываемую при возбуждении определенного сигнала). 488 Глава 11. Распределенная обработка данных В языке программирования могут быль предусмотрены дополнительные исключения — для этого транслятор языка вставляет дополнительные инструкции в выполняемый код. Например, чтобы обнаружить исключение !Мех СПес1, причиной которого явился выход индекса элемента массива за допустимый диапазон его изменения, транслятор вставляет явную последовательность команд при каждой ссылке на массив (например, А[1. Д), которая определяет, находятся ли значения 1 и ) в объявленных границах массива. Таким образом, если только проверка исключений не обеспечивается аппаратной частью компьютера или операционной системой, проверка исключений требует определенного программного моделирования.
Часто затраты на такую проверку достаточно велики — как в отношении времени выполнения, так и в отношении объема памяти, необходимой для хранения кода. Например, может оказаться, что проверка того, попадают ли индексы для элемента массива А11. 1) в установленный диапазон, займет больше времени, чем сама операция извлечения этого элемента. По причине этих дополнительных затрат большинство языков предусматривают средство отключения проверки возникновения исключений в тех частях программы, где, по мнению программиста, это абсолютно безопасно (наприме1х конструкция ргдоед 5цгргезз(!поех СПес1) в языке Аоа). Если в программе сгенерировано исключение, передача управления обработчику исключений, содержащемуся в этой же программе, обычно реализуется командой перехода непосредственно на начало кода обработчика. Распространение исключений от точек порождения вперед по динамической цепи вызовов подпрограмм можно реализовать, используя динамическую цепь, сформированную точками возврата в записях активаций подпрограмм из центрального стека, как обсуждалось ранее.
По мере распространения исключения по динамической цепи каждая активация подпрограммы должна быть завершена при помощи специальной формы команды возврата, которая возвращает управление вызывающей подпрограмме и снова порождает исключение, но уже в вызывающей подпрограмме. Эта последовательность возвратов продолжается до тех пор, пока динамическая цепочка вызовов подпрограмм не приведет нас к той подпрограмме, в которой присутствует обработчик сгенерированного исключения, Когда нужный обработчик найден, он вызывается точно так же, как вызывается обычная подпрограмма. Когда обработчик завершает свое выполнение, он, однако, лшжет также завершить содержащую его подпрограмму, приводя, таким образом, к двум нормальным возвратам из подпрограмм, следующим один немедленно за другим.
Когда таким способом будет «пройдена» динамическая цепочка до последнего нормального возврата в подпрограмму, то именно эта подпрограмма продолжает свое дальнейшее выполнение обычным образом. Утверждения Понятие утверждения (аззегг1оп) является родственным понятию исключения. Утверждение — это просто некоторый оператор, предполагающий некоторые отношения межлу объектами данных в программе, как, например, следующий оператор С+ч-: 111лс1иде < дддегг.п > ддддгг 1Х>у>1). 11.1. Различные варианты управления подпрограммами 489 Предопределенный макрос' С++ генерирует следующий условный оператор: !Г 1яяу+И ( /* лечить сообиеиия об оиибке *У ) Утверждение — это удобный способ тестирования программы на наличие ошибок без сложного кодирования, усложняющего исходный текст программы.
Когда разработка программы завершена, утверждение аззегь может остаться в программе в качестве документации (см, раздел 4.2.4), а макрос можно изменить таким образом, чтобы он не генерировал никаких операторов и оставался в программе просто в виде комментария. 11.1.2. Сопрограммы Допустим, что мы отказались от ограничения 3 из раздела 11.1, то есть разрешили передавать управление из вызванной подпрограммы в вызывающую, до того как вызванная подпрограмма завершит свое выполнение нормальным образом.
Такие полпрограммы называются согьрог)заясиами. Кола сопрограмма получает управление от другой подпрограммы, она выполняется лишь частично, а затем приостанавливается и возвращает управление вызвавшей ее подпрограмме. Впоследствии в некоторой точке вызывающая программа может возобновить (гезои1е) выполнение сопрограммы с той точки, в которой выполнение было ранее приостановлено.
Отметим симметрию, введенную здесь в структуру вызывающей и вызываемой подпрограмм. Если А вызывает подпрограмму В как сопрограмму, то В выполняется некоторое время и возвращает управление в подпрограмму А, как сделала бы любая обычная подпрограмма. Когда А снова передает управление В при помощи оператора геьци1е В, то В снова выполняется некоторое время и возвращает управление в подпрограмму А, как обычная подпрограмма. Таким образом, для А сопрограмма В выл лядит как обычная подпрограмма. Но если посмотреть на этот процесс с другой точки зрения, из подпрограммы В, то мы увидим аншюгичную ситуацию. Подпрограмма В в середине своего выполнения возобновляет выполнение А.
Подпрограмма А выполняется некоторое время и возвращает управление В. Подпрограмма В продолжает свое выполнение в течение некоторого времени и возвращает управление А. Подпрограмма А продолжает свое выполнение в течение некоторого времени и возвращает управление В, А выглядит с точки зрения подпрограммы В как вполне обычная подпрограмма. Название сопрограмма происходит именно от этой описанной симметрии. Взаимоотношение между двумя сопрограммами строится не по принципу родитель-потомок или вызывающий-вызываемый; это скорее взаимоотношение двух равных структур, которые передают друг другу управление по мере выполнения, причем ни одна из них не контролирует другую явным образом (рис. 11.1).
В настоящее время сопрограммы явля ются общей структурой управления только в языках дискретного моделирования (см. раздел 11.1.3). Тем не менее для многих алгоритмов они являются более естественной структурой управления, чем обычная иерархия вызовов подпрограмм.
Более того, простая структура сопрограмм вогиногихязыкахлегкоможетбытьсмоделированаспомощьюоператорадобои пе- В Сч.+ амеге яияяетея макроопределением. — Прииьеч. науч. лед. 490 Глава 11. Распределенная обработка данных ременной тпочки возобновления, определяющей метку того оператора, с которого должно возобновиться выполнение. Сопрограмма А Сопрограмма о Рис. 11.1. Передача управления между сопрограммами Реализация.
Команда левике, которая передает управление от одной сопрограммы другой, предписывает возобновление некоторой определенной активапии сопрограммы. Если существует несколько рекурсивных активаций сопрограммы В, то оператор гезиее В не имеет точного значения. По этой причине проще всего представлять себе сопрограммы в контексте, когда в каждый момент времени существует только одна активация данной сопрограммы. Это ограничение позволяет нам использовать для реализации сопрограмм технику, аналогичную той, которая использовалась для простых структур вызова-возврата (см.
раздел 8.3.2). В начале выполнения одна запись активации статически размещается в памяти в виде расширения сегмента кода сопрограммы. В записи активации резервируется специальное поле, называемое теперь точкой возобновления, для сохранения старого значения ~р указателя С1Р, когда команда гегщяе передает управление другой сопрограмме.
Но в отличие от точки возврата простой подпрограммы, это поле точки возобновления в программе В используется для хранения значения 1р самой подпрограммы В. Выполнение оператора гезияе В в сопрограмме А происходит в два этапа. 1. Текущее значение С!Р сохраняется в поле точки возобновления записи ак- тивации сопрограммы А, 2. Значение 1р, хранящееся в поле точки возобновления сопрограммы В, извлекается из записи активации сопрограммы В и присваивается указателю С1Р, чтобы инициировать передачу управления правильной команде сопрограммы В. Так как не существует явной команды возврата, то сопрограмме В нет необходимости «знать», что сопрограмма Я передала ей управление.