Пример: использование обработчиков завершения для повышения качества программ

Пример: использование обработчиков завершения для повышения качества программ

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

В программе toupper (программа 4.2) эти моменты иллюстрируются с привлечением идей, почерпнутых в программном коде предшествующих примеров. toupper обрабатывает несколько файлов, имена которых указываются в командной строке, переписывая их с преобразованием всех букв в верхний регистр. Имена преобразованных файлов получаются путем добавления префикса UC_ к исходным именам, и согласно "спецификации" программы запись поверх существующих файлов не производится. Преобразование файлов осуществляется в памяти машины, поэтому для каждого файла выделяется большая буферная область (достаточная для размещения всего файла). Кроме того, чтобы исключить любую возможность изменения файлов другими процессами, а также для того, чтобы вновь создаваемые выходные файлы строго соответствовали преобразованным входным файлам, оба вида файлов блокируются во время обработки. Понятно, что на каждой стадии обработки существует вероятность возникновения самых различных сбойных ситуаций, но в программе должна быть предусмотрена защита от подобных ошибок, и она должна располагать средствами, позволяющими ей восстановить свое нормальное состояние и попытаться обработать все остальные файлы, имена которых были указаны в командной строке. Программа 4.2 решает все эти задачи, обеспечивая разблокирование файлов во всех необходимых случаях без применения громоздкой логики операторов ветвления, к которым пришлось бы прибегнуть, если бы не были использованы средства SEH. Более подробные комментарии к программе содержатся в программном коде, находящемся на Web-сайте книги.

Программа 4.2. toupper: обработка файлов с восстановлением нормального состояния программы после сбоев

/* Глава 4. Команда toupper. */

/* Преобразование содержимое одного и более файлов с заменой всех букв на прописные. Имя выходного файла получается из имени входного файла добавлением к нему префикса UC_. */

#include "EvryThng.h"

int _tmain(DWORD argc, LPTSTR argv[]) {

 HANDLE hIn = INVALID_HANDLE_VALUE, hOut = INVALID_HANDLE_VALUE;

 DWORD FileSize, nXfer, iFile, j;

 CHAR OutFileName [256] = "", *pBuffer = NULL;

 OVERLAPPED ov = {0, 0, 0, 0, NULL}; /* Используется для блокирования файлов. */

 if (argc <= 1) ReportError(_T("Использование: toupper файлы"), 1, FALSE);

 /* Обработать все файлы, указанные в командной строке. */

 for (iFile = 1; iFile < argc; iFile++) __try { /* Блок исключений. */

  /* Все дескрипторы файлов недействительны, pBuffer == NULL, а файл OutFileName пуст. Выполнение этих условий обеспечивается обработчиками. */

  _stprintf(OutFileName, "UC_%s", argv[iFile]);

  __try { /* Внутренний блок try-finally. */

   /* Ошибка на любом шаге сгенерирует исключение, и следующий */

   /* файл будет обрабатываться только после "уборки мусора". */

   /* Объем работы по очистке зависит от того, в каком месте */

   /* программы возникла ошибка. */

   /* Создать выходной файл (завершается с ошибкой, если файл уже существует). */

   hIn = CreateFile(argv[iFile], GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);

   if (hIn == INVALID_HANDLE_VALUE) ReportException(argv[iFile], 1);

   FileSize = GetFileSize(hIn, NULL);

   hOut = CreateFile(OutFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);

   if (hOut == INVALID_HANDLE_VALUE) ReportException(OutFileName, 1);

   /* Распределить память под содержимое файла. */

   pBuffer = malloc(FileSize);

   if (pBuffer == NULL) ReportException(_T("Ошибка при распределении памяти"), 1);

   /* Блокировать оба файла для обеспечения целостности копии. */

   if (!LockFileEx(hIn, LOCKFILE_FAIL_IMMEDIATELY, 0, FileSize, 0, &ov) ReportException(_T("Ошибка при блокировании входного файла"), 1);

   if (!LockFileEx(hOut, LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY, 0, FileSize, 0, &ov) ReportException(_T("Ошибка при блокировании выходного файла "), 1);

   /* Считать данные, преобразовать их и записать в выходной файл. */

   /* Освободить ресурсы при завершении обработки или возникновении */

   /* ошибки; обработать следующий файл. */

   if (!ReadFile(hIn, pBuffer, FileSize, &nXfer, NULL)) ReportException(_T("Ошибка при чтении файла"), 1);

   for (j = 0; j < FileSize; j++) /* Преобразовать данные. */

    if (isalpha(pBuffer [j])) pBuffer[j] = toupper(pBuffer [j]);

   if(WriteFile(hOut, pBuffer, FileSize, &nXfer, NULL)) ReportException(T("Ошибка при записи в файл"), 1);

  } __finally {

   /*Освобождение блокировок, закрытие дескрипторов файлов,*/

   /*освобождение памяти и повторная инициализация */

   /*дескрипторов и указателя. */

   if (pBuffer != NULL) free (pBuffer);

   pBuffer = NULL;

   if (hIn != INVALID_HANDLE_VALUE) {

    UnlockFileEx(hIn, 0, FileSize, 0, &ov);

    CloseHandle(hIn);

    hIn = INVALID_HANDLE_VALUE;

   }

   if (hOut != INVALID_HANDLE_VALUE) {

    UnlockFileEx(hOut, 0, FileSize, 0, &ov);

    CloseHandle(hOut);

    hOut = INVALID_HANDLE_VALUE;

   }

   _tcscpy(OutFileName, _T(""));

  }

 }

 /* Конец основного цикла обработки файлов и блока try. */

 /* Обработчик исключений для тела цикла. */

 __except(EXCEPTION_EXECUTE_HANDLER) {

  _tprintf(_T("Ошибка при обработке файла %s "), argv[iFile]);

  DeleteFile (OutFileName);

 }

 _tprintf(_T("Обработаны все файлы, кроме указанных выше "));

 return 0;

}

Поделитесь на страничке

Следующая глава >

Похожие главы из других книг

1.2.5. Использование сеансов. Автозапуск программ и сохранение сеанса

Из книги Fedora 8 Руководство пользователя автора Колисниченко Денис Николаевич

1.2.5. Использование сеансов. Автозапуск программ и сохранение сеанса Разгар рабочего дня. Запущено много программ, открыто много документов. Вам нужно отлучиться до конца дня, поэтому нужно выключить компьютер. Вам не хочется завтра открывать все эти документы заново?


Использование внешних программ

Из книги Основы объектно-ориентированного программирования автора Мейер Бертран

Использование внешних программ Внешние программы являются частью ОО-метода, помогая сочетать старое ПО с новым. Любой метод проектирования ПО, допускающий возможность повторного использования, должен допускать программный код, написанный на других языках. Трудно было


Пример: сервер, использующий порты завершения ввода/вывода

Из книги Системное программирование в среде Windows автора Харт Джонсон М

Пример: сервер, использующий порты завершения ввода/вывода Программа 14.4 представляет видоизмененный вариант программы serverNP (программа 11.3), в котором используются порты завершения ввода/вывода. Этот сервер создает небольшой пул серверных потоков и больший пул


ПРИЛОЖЕНИЕ А Использование примеров программ

Из книги Справочник по PHP автора

ПРИЛОЖЕНИЕ А Использование примеров программ На Web-сайте книги (http://www.awprofessional.com/titles/0321256190) находится zip-архив, который содержит исходные тексты всех примеров программ, а также соответствующие заголовочные файлы, служебные функции, файлы проектов и исполняемые файлы. Ряд


Обзор обработчиков

Из книги Сетевые средства Linux автора Смит Родерик В.

Обзор обработчиков handler_openЭтот обработчик должен взять на себя всю работу по открытию базы данных для группы сессий с именем, которое было передано ей в параметрах.Синтаксис:bool handler_open(string $save_path, string $session_name)Функция вызывается, когда вызывается session_start(). Обработчик должен


Использование программ поддержки NetBEUI

Из книги Разработка приложений в среде Linux. Второе издание автора Джонсон Майкл К.

Использование программ поддержки NetBEUI Пакет, предназначенный для поддержки стека NetBEUI, содержит файл README, в котором полностью описан процесс инсталляции. Установка пакета может быть выполнена двумя способами. Следуя одному из них, надо отредактировать файл Makefile, указав в


12.4. Написание обработчиков сигналов

Из книги Краткое введение в программирование на Bash автора Родригес Гарольд

12.4. Написание обработчиков сигналов Хотя обработчик сигнала выглядит подобно обычной функции С, он не вызывается так, как она. Вместо того чтобы быть частью нормальной последовательности вызовов программы, обработчик вызывается ядром. Ключевое различие между этими


Коды завершения программ

Из книги Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform автора Кёртен Роб

Коды завершения программ Большинство программ возвращают в операционную систему какое-то число, показывающее, насколько удачно программа завершила свою работу. Например, man-страница grep говорит, что grep вернет 0, если заданный шаблон найден, и 1, если совпадений не найдено.


Написание обработчиков прерываний

Из книги Искусство программирования на языке сценариев командной оболочки автора Купер Мендель

Написание обработчиков прерываний Давайте посмотрим, как настроить обработчики прерываний — вызовы, характеристики и кое-какие стратегии


Подключение обработчиков прерываний

Из книги Linux программирование в примерах автора Роббинс Арнольд

Подключение обработчиков прерываний Для подключения к источнику прерывания воспользуйтесь функцией InterruptAttach() или InterruptAttachEvent().#include <sys/neutrino.h>int InterruptAttachEvent(int intr, const struct sigevent *event, unsigned flags);int InterruptAttach(int intr, const struct sigevent* (*handler)(void *area, int id), const void *area, int size, unsigned flags);Параметр


Пример 10-24. Использование case

Из книги QT 4: программирование GUI на С++ автора Бланшет Жасмин

Пример 10-24. Использование case #!/bin/bashecho; echo "Нажмите клавишу и затем клавишу Return."read Keypresscase "$Keypress" in [a-z] ) echo "буква в нижнем регистре";; [A-Z] ) echo "Буква в верхнем регистре";; [0-9] ) echo "Цифра";; * ) echo "Знак пунктуации, пробел или что-то другое";;esac # Допускается указыватль


3.2.1.7. Использование персональных программ распределения

Из книги Windows 10. Секреты и устройство автора Алмаметов Владимир

3.2.1.7. Использование персональных программ распределения Набор функций с malloc() является набором общего назначения по выделению памяти. Он должен быть способен обработать запросы на произвольно большие или маленькие размеры памяти и осуществлять все необходимые учетные


9.1.6. Использование статуса завершения порожденного процесса

Из книги автора

9.1.6. Использование статуса завершения порожденного процесса Когда процесс заканчивается, нормальным ходом событий для ядра является освобождение всех его ресурсов. Ядро сохраняет статус завершения законченного процесса, также, как сведения о ресурсах, которые он