Windows для профессионалов

       

Проверьте себя: FuncaDoodleDoo


Посмотрим, отгадаете ли Вы, что именно возвращает следующая функция

DWORD FuncaDoodleDoo()
{
DWORD dwTerrip = 0;

while (dwTemp < 19)
{

__try
{
if (dwTemp == 2) continue;
if (dwTemp == 3) break;
}

__finally { dwTernp++; }

dwTemp++;

}

dwTemp += 10;
return(dwTemp);

}

Проанализируем эту функцию шаг за шагом. Сначала dwTemp приравнивается 0. Код в блоке try выполняется, но ни одно из условий в операторах if не дает TRUE, и поток управления естественным образом переходит в блок finаllу, где dwTemp увели чивается до 1. Затем инструкция после блока finаllу снова увеличивает значение dwTemp, приравнивая его 2.

На следующей итерации цикла dwTemp равно 2, поэтому выполняется оператор continue в блоке try, Без обработчика завершения, вызывающего принудительное вы полнение блока finаllу перед выходом из try, управление было бы передано непосред ственно в начало цикла while, значение dwTemp больше бы не менялось — и мы в бесконечном цикле! В присутствии же обработчика завершения система обнаружи вает, что оператор continue приводит к преждевременному выходу из try, и передает управление блок finаllу. Значение dwTemp в нем увеличивается до 3, но код за этим

блоком не выполняется, так как управление снова передается оператору continue, и мы вновь в начале цикла.

Теперь обрабатываем третий проход цикла. На этот раз значение выражения в первом if равно FALSE, а во втором — TRUE. Система снова перехватывает нашу по пытку прервать выполнение блока try и обращается к коду finаllу. Значение dwTemp увеличивается до 4. Так как выполнен оператор break, выполнение возобновляется после тела цикла. Поэтому код, расположенный за блоком finаllу (но в теле цикла), не выполняется. Код, расположенный за телом цикла, добавляет 10 к значению dwTemp, что дает в итоге 14, — это и есть результат вызова функции. Даже не стану убеж дать Вас никогда не писать такой код, как в FuncaDoodleDoo. Я-то включил continue и break в середину кода, только чтобы продемонстрировать поведение обработчика завершения.

Хотя обработчик завершения справляется с большинством ситуаций, в которых выход из блока try был бы преждевременным, он не может вызвать выполнение бло ка finally при завершении потока или процесса. Вызов ExitThread или ExitProcess сра зу завершит поток или процесс — без выполнения какого-либо кода в блоке finаllу. То же самое будет, если Ваш поток или процесс погибнут из-за того, что некая програм ма вызвала TerminateThread или TerminateProcess. Некоторые функции библиотеки С (вроде abort). в свою очередь вызывающие ExitProcess, тоже исключают выполнение блока finаllу. Раз Вы не можете запретитьдругой программе завершение какого-либо из своих потоков, или процессов, так хоть сами не делайте преждевременных вызо вов ExitThread и ExitProcess.



Содержание раздела