Пример: обработка ошибок как исключений

Пример: обработка ошибок как исключений

В предыдущих примерах для обработки ошибок при выполнении системных вызовов и других ошибок используется функция ReportError. Эта функция прекращает выполнение процесса, если программист указал, что данная ошибка является критической. Вместе с тем, такой подход препятствует нормальному выходу из программы и не обеспечивает возможность продолжения работы программы после устранения последствий ошибки. Так, после отказа от задачи, которая привела к возникновению сбоя, может потребоваться уничтожение временных файлов, созданных в процессе работы программы, или переход программы к выполнению других задач. Функции ReportError присущи и другие ограничения, перечень которых приводится ниже.

• Даже в тех случаях, когда было бы достаточно прекратить выполнения только одного потока, критическая ошибка приводит к остановке всего процесса (главу 7).

• Вместо завершения процесса может оказаться желательным продолжение выполнения программы.

• Во многих случаях становится невозможным освобождение ресурсов синхронизации (глава 8), например мьютексов.

При прекращении выполнения процесса (но не потоки) открытые дескрипторы будут закрываться, однако при этом необходимо учитывать другие отрицательные факторы.

Решение заключается в написании новой функции — ReportException. Если ошибка не является критической, эта функция вызывает функцию ReportError (разработанную в главе 2), которая выводит сообщение об ошибке. В случае же возникновения критической ошибки будет сгенерировано исключение. Система будет использовать обработчик исключений из вызывающего try-блока, и поэтому в действительности характер исключения может быть некритическим, если обработчик предоставляет программе возможность восстановиться после сбоя. По существу, функция ReportException дополняет обычные программные методы защиты от ошибок, ранее ограниченные функцией ReportError. В случае обнаружения ошибки обработчик позволяет программе продолжить свою работу после выполнения необходимых восстановительных действий. Эти возможности иллюстрирует программа 4.2.

Функция ReportException представлена в программе 4.1. Необходимые определения и заголовочные файлы не указаны, поскольку эта функция находится в том же модуле исходного кода, что и функция ReportError. 

Программа 4.1. ReportException: функция вывода сообщений об исключениях 

/* Расширение функции ReportError для генерации формируемого приложением кода исключения вместо прекращения выполнения процесса. */

VOID ReportException(LPCTSTR UserMessage, DWORD ExceptionCode)

/* Вывести сообщение о некритической ошибке. */

{

 ReportError(UserMessage, 0, TRUE);

 /* Если ошибка критическая, сгенерировать исключение. */

 if (ExceptionCode != 0) RaiseException((0x0FFFFFFF & ExceptionCode) | 0xE0000000, 0, 0, NULL);

 return;

}

Функция ReportException используется в нескольких последующих примерах. 

Модель сигналов, используемая в UNIX, значительно отличается от SEH. Сигналы могут быть пропущены или игнорированы, и логика их работы иная. Тем не менее, у этих моделей имеются и общие черты.

Значительная часть поддержки обработки сигналов в UNIX обеспечивается библиотекой С, ограниченная версия которой доступна также под управлением Windows. Во многих случаях в программах Windows вместо сигналов можно воспользоваться обработчиками управляющих сигналов консоли, описанными в конце данной главы.

Некоторые сигналы соответствуют исключениямWindows.

Перечень в некоторой мере ограниченных соответствий "сигнал-исключение" представлен ниже:

• SIGILL — EXCEPTION_PRIV_INSTRUCTION

• SIGSEGV — EXCEPTION_ACCESS_VIOLATION

• SIGFPE — семь различных исключений, связанных с выполнением операций над числами с плавающей точкой, например EXCEPTION_FLT_DIVIDE_BY_ZERO

• SIGUSR1 и SIGUSR2 — исключения, определяемые приложением

Функции RaiseException соответствует функция библиотеки С raise.

В Windows сигналы SIGILL, SIGSEGV и SIGFPE не генерируются, хотя функция raise может генерировать один из них. Сигнал SIGINT в Windows не поддерживается.

Функция UNIX kill (kill не входит в состав стандартной библиотеки С), которая посылает сигнал другому процессу, может быть сопоставлена функции Windows GenerateConsoleCtrlEvent (глава 6). Для ограниченного варианта SIGKILL в Windows имеются аналоги в виде функций TerminateProcess и TerminateThread, с помощью которых один процесс (или поток) может уничтожить другой, хотя при использовании этих функций необходимо соблюдать осторожность (см. главы 6 и 7).