Глобальная раскрутка
Когда фильтр исключений возвращает EXCEPTION_EXECUTE_HANDLER, системе при ходится проводить глобальную раскрутку Она приводит к продолжению обработки всех незавершенных блоков try-finally, выполнение которых началось вслед за блоком try-except, обрабатывающим данное исключение. Блок-схема на рис. 24-2 поясняет, как система осуществляет глобальную раскрутку Посматривайте на эту схему, когда бу дете читать мои пояснения к следующему примеру
Рис. 24-2. Так система проводит глобальную раскрутку
void FuncOSTimpy1()
{
// 1 Что-то делаем здесь
...
__try
{
// 2 Вызываем другую функцию
FuncORen1();
// этот код никогда не выполняется
}
__except (/* 6 Проверяем фильтр исключений */ EXCEPTION_EXECUTE,HANDLER)
{
// 8 После раскрутки выполняется атот обработчик
MessageBox(....);
}
// 9 Исключение обработано - продолжаем выполнение ...
}
void FuncORen1()
{
DWORD dwTemp = 0;
// 3. Что-то делаем здесь
...
__try
{
// 4. Запрашиваем разрешение на доступ к защищенным данным
WaitForSingleObject(g_nSem, INFINITE);
// 5. Изменяем данные, и здесь генерируется исключение
g_dwProtectedData = 5 / dwTemp;
}
__finally
{
// 7. Происходит глобальная раскрутка, так как
// фильтр возвращает FXCFPTTON_EXECUTE_HANDLER
// Даем и другим попользоваться защищенными данными
ReleaseSemaphore(g_hScm, 1, NULL);
}
// сюда мы никогда не попадем
...
}
FuncOStimpyl и FuncORen1 иллюстрируют самые запутанные аспекты структурной обработки исключений. Номера в начале комментариев показывают порядок выпол нения, в котором сходу не разберешься, но возьмемся за руки и пойдем вместе.
FuncOStimpy1 начинает выполнение со входа в свой блок try и вызова FuncORen1. Последняя тоже начинает со входа в свой блок try и ждет освобождения семафора. Завладев им, она пытается изменить значение глобальной переменной g_dwProtected Data. Деление на нуль возбуждает исключение. Система, перехватив управление, ищет блок try, которому соответствует блок except. Поскольку блоку try функции FuncORenl соответствует 6лок finally, система продолжает поиск и находит блок try в FuncOStim py1, которому как раз и соответствует блок except.
Тогда система проверяет значение фильтра исключений в блоке except функции FuncOStimpy1. Обнаружив, что оно — EXCEPTION_EXECUTE_HANDLER, система начи нает глобальную раскрутку с блока finally в функции FuncORen1. Заметьте: раскрутка происходит до выполнения кода из блока except в FuncOStimpy1. Осуществляя глобаль ную раскрутку, система возвращается к последнему незавершенному блоку try и ищет теперь блоки try, которым соответствуют блоки finally. В нашем случае блок finally находится в функции FuncORen1.
Мощь SEH по-настоящему проявляется, когда система выполняет код finally в Func ORen1. Из-за его выполнения семафор освобождается, и поэтомудругой поток полу чает возможность продолжить работу. Если бы вызов ReleaseSemapbore в блоке finally отсутствовал, семафор никогда бы не освободился.
Завершив выполнение блока finally, система ищет другие незавершенные блоки finally. В нашем примере таких нет. Дойдя до блока except, обрабатывающего исклю чение, система прекращает восходящий проход по цепочке блоков. В этой точке гло бальная раскрутка завершается, и система может выполнить код в блоке except,
Вот тук и работает структурная обработка исключений. Вообще-то, SEH — штука весьма трудная для понимания: в выполнение Вашего кода вмешивается операцион ная система Код больше не выполняется последовательно, сверху вниз; система уста навливает свой порядок — сложный, но все же предсказуемый. Поэтому, следуя блок схемам на рис, 24-1 и 24-2, Вы сможете уверенно применять SEH.
Чтобы лучше разобраться в порядке выполнения кода, посмотрим на происходя щее под другим углом зрения. Возвращая EXCEPTION_EXECUTE_HANDLER, фильтр сообщает операционной системе, что регистр указателя команд данного потока дол жен быть установлен на код внутри блока except Однако зтот регистр указывал на код внутри блока try функции FuncORen1. А из главы 23 Вы должны помнить, что всякий раз, когда поток выходит из блока try, соответствующего блок finally, обязательно вы полняется код в этом блоке finally. Глобальная раскрутка как раз и является тем меха низмом, который гарантирует соблюдение этого правила при любом исключении.