Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Программирование лекции.doc
Скачиваний:
49
Добавлен:
12.11.2019
Размер:
5.53 Mб
Скачать

19.1. Векторы прерываний

Конечно, неизбежное "сваливание" программы при возникновении любой ошибки – ситуация довольно неприятная. Было бы неплохо, если при ошибке выполнялась бы какая-то собственная процедура, а затем выполнение программы продолжалось. К счастью, в программировании нет ничего невозможного.

В самых младших адресах оперативной памяти операционная система хранит векторы прерываний (interrupt vectors). Вектор прерывания представляет собой указатель на адрес в памяти, начиная с которого расположена программа обработки этого прерывания. Самое важное – вектор прерывания можно изменить и заставить компьютер при возникновении ошибки выполнять собственный программный код. Каждое прерывание (и его вектор) имеет свой номер от 0 до 255. Например, нажатие клавиши вызывает прерывание с номером 9, движение мыши – с номером 13 и т.д.

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

Кстати, ряд прерываний происходит достаточно часто. Пользователь нажимает на клавиши, двигает мышь… Прерывание таймера компьютера происходит каждую 1/18 с. Соответственно программа-обработчик обязана быть небольшой, чтобы не тормозить работу машины.

Помимо этого, обработчик прерывания должен обеспечивать выполнение очень важного условия. Обработчик вклинивается в поток команд процессора. Чтобы ничего не нарушить, после окончания работы обработчика все регистры процессора должны находиться в том же состоянии, что и в момент начала его работы. Тогда компьютер "не заметит" прерывания и будет работать дальше, как ни в чем не бывало (Рис. 19 .72).

Рис. 19.72. Функции обработчика прерывания.

Как этого достичь? Очевидно, в начале работы обработчик должен где-то запомнить содержимое регистров процессора, а при окончании - восстановить его.

19.1.1Хранение данных в стеке

При входе в обработчик прерывания, он сохраняет регистры процессора в особой структуре данных, называемой стеком (stack). Стек работает по принципу "первым вошел – последним вышел" (Рис. 19 .73).

Рис. 19.73. Стек.

Хорошим аналогом стека является магазин автомата Калашникова (программистская шутка гласит, что АКМ – лучшее средство для превращения стека в очередь).

При извлечении значений из стека нужно помнить о том, что теперь они будут идти в обратном порядке. Если мы занесли в стек сначала а, потом b, потом c, то первым извлечется с, затем b и, наконец, а.

19.2. Контроль ввода-вывода

Наиболее часто ошибки возникают при работе с файлами на внешних устройствах. Может произойти сбой записи на дискету, нерадивый пользователь норовит забыть вставить дискету в дисковод, другой любит класть диски в CD ROM не той стороной и т.д. В результате, если не принять особых мер, будут происходить фатальные ошибки и вся программа позорно "свалится" из-за такой мелочи, как ошибка записи или считывания файла.

Существует несколько способов решения указанной проблемы. Во-первых, надо сообщить транслятору, что в данном месте программы надо реагировать на ошибки ввода-вывода спокойнее, а точнее говоря, вовсе их не замечать. Указания транслятору даются при помощи так называемых директив.

Директива – особый объект в тексте программы, управляющий режимами компиляции программы. На Паскале директивы записываются в фигурных скобках, причем сразу после открывающей скобки идет знак доллара, а за ним – имя директивы и, если необходимо, дополнительные параметры.

За ввод-вывод отвечает директива I.

{$I-} – отключить контроль ввода-вывода; {$I+} – включить контроль ввода-вывода.

Таким образом, чтобы обезопасить процедуру записи информации в файл, следует написать:

{$I-}

Writeln(f,s);

{$I+}

Теперь программа не будет реагировать на сбой при записи. Но как же узнать, не случилось что-то страшное, раз контроль отключен? Для этого есть функция IORESULT, которая возвращает код результата выполнения последней операции ввода-вывода. Если это 0 – все нормально, иначе – ошибка. После вызова функции ее значение сбрасывается, поэтому обычно его сохраняют в переменную. Проверка выглядит следующим образом:

{$I-}

Writeln(f,s); IF IOResult<>0 THEN WriteLn(’Ошибка записи’)

{$I+}