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

А сейчас разберем другой сценарий,


А сейчас разберем другой сценарий, в котором обработка завершения действитель но полезна:

DWORD Funcfurter1()
{
DWORD dwTemp;

// 1. Что-то делаем здесь

...

__try
{
// 2. Запрашиваем разрешение на доступ
// к защищенным данным, а затем используем их
WaitForSingleObject(g_hSem, INFINITE);
dwTemp = Funcinator(g_dwProtectedData);
}

_finally
{
// 3. Даем и другим попользоваться защищенными данными
RelcaseSemaphore(g_hSem, 1, NULL);
}

// 4. Продолжаем что-то делать
return(dwTemp);
}

Допустим, в функции Funcinator, вызванной из блока try, — "жучок", из-за которо го возникает нарушение доступа к памяти. Без SEH пользователь в очередной раз уви дел бы самое известное диалоговое окно Application Error. Стоит его закрыть — за вершится и приложение Если бы процесс завершился (из-за пеправильногодоступа к памяти), семафор остался бы занят — соответственно и ожидающие его потоки не получили бы процессорное время. Но вызов ReleaseSemaphore в блоке finаllу гаранти рует освобождение семафора, дажс ссли нарушение доступа к памяти происходит в какой-то другой функции.

Раз обработчик завершения — такое мощное средство, способное перехватывать завершение программы из-за неправильного доступа к памяти, можно смело рассчи тывать ична то, что оно также перехватит комбинации setjump/longump и элементар ные операторы типа break и continue.



Следующий фрагмент демонстрирует использование встраиваемой функции Abnor malTermination:

DWORD Funcfurter2()
{

DWORD dwTemp;



// 1 Что-то делаем здесь

...

1 Встраиваемая функция (intrinsic function) — особая функция, распознаваемая компилято ром Вместо генерации вызова такой функции он подставляет в точке вызова ее код. При мером встраиваемой функции является memcpy (если указан ключ компилятора /Oi). Встре чая вызов memcpy, компилятор подставляет ec код непосредственно в вызывающую функ цию Обычно это ускоряет работу программы ценой увеличения ее размера Функция AbnormalTermination отличается от тетсру тем, что существует только во встраиваемом варианте. Ее нет ни в одной библиотеке С.

__try {

// 2. Запрашиваем разрешение на доступ
// к защищенным данным, а затем используем их
WaitForSingleObject(g_hSem, INFINITE);

dwTemp = Funcinator(g_dwProtectedData);

}

__finally
{

// 3. Даем и другим попользоваться защищенными данными
ReleaseSemaphore(g_hSem, 1, NULL);

if (!AbnormalTermination())
{

// в блоке try не было ошибок - управление
// передано в блок finally естественным образом

...

}

else

{

// что-то вызвало исключение, и, так как в блоке try
// нет кода, который мог бы вызвать преждевременный
// выход, блок finally выполняется из-за глобальной
// раскрутки
// если бы в блоке try был оператор goto, мы бы
// не узнали, как попали сюда

}

}

// 4. Продолжаем что-то делать

return(dwТemp);

}

Теперь Вы знаете, как создавать обработчики завершения. Вскоре Вы увидите, что они могут быть еще полезнее и важнее, — когда мы дойдем до фильтров и обработ чиков исключений (в следующей главе). А пока давайте суммируем причины, по ко торым следует применять обработчики завершения.

  • Упрощается обработка ошибок — очистка гарантируется и проводится в од ном месте.

  • Улучшается восприятие текста программ.

  • Облегчается сопровождение кода.

  • Удается добиться минимальных издержек по скорости и размеру кода — при условии правильного применения обработчиков.



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