Пример: преобразование файлов с использованием перекрывающегося ввода/вывода и множественной буферизации

Пример: преобразование файлов с использованием перекрывающегося ввода/вывода и множественной буферизации

Программа 2.4 (atou) осуществляла преобразование ASCII-файла к кодировке UNICODE путем последовательной обработки файла, а в главе 5 было показано, как выполнить такую же последовательную обработку с помощью отображения файлов. В программе 14.1 (atouOV) та же самая задача решается с использованием перекрывающегося ввода/вывода и множественных буферов, в которых хранятся записи фиксированного размера.

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

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

Рис. 14.1. Модель асинхронного обновления файла

Программа 14.1. atouOV: преобразование файла с использованием перекрывающегося ввода/вывода 

/* Глава 14. atouOV

   Преобразование файла из кодировки ASCII в кодировку Unicode с использованием перекрывающегося ввода/вывода. Программа работает только в Windows NT. */

#include "EvryThng.h"

#define MAX_OVRLP 4 /* Количество перекрывающихся операций ввода/вывода.*/ 

#define REC_SIZE 0x8000 /* 32 Кбайт: Минимальный размер записи, обеспечивающий приемлемую производительность. */

#define UREC_SIZE 2 * REC_SIZE

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

 HANDLE hInputFile, hOutputFile;

 /* Каждый из элементов определенных ниже массивов переменных */

 /* и структур соответствует отдельной незавершенной операции */

 /* перекрывающегося ввода/вывода. */

 DWORD nin[MAX_OVRLP], nout[MAX_OVRLP], ic, i;

 OVERLAPPED OverLapIn[MAX_OVRLP], OverLapOut[MAX_OVRLP];

 /* Необходимость использования сплошного, двумерного массива */

 /* диктуется Функцией WaitForMultipleObjects. */

 /* Значение 0 первого индекса соответствует чтению, значение 1 – записи.*/

 HANDLE hEvents[2][MAX_OVRLP];

 /* В каждом из определенных ниже двух буферных массивов первый индекс */

 /* нумерует операции ввода/вывода. */

 CHAR AsRec[MAX_OVRLP][REC_SIZE];

 WCHAR UnRec[MAX_OVRLP][REC_SIZE];

 LARGE_INTEGER CurPosIn, CurPosOut, FileSize;

 LONGLONG nRecord, iWaits;

 hInputFile = CreateFile(argv[1], GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);

 hOutputFile = CreateFile(argv[2], GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_OVERLAPPED, NULL);

 /* Общее количество записей, подлежащих обработке, вычисляемое */

 /* на основе размера входного файла. Запись, находящаяся в конце, */

 /* может быть неполной. */

 FileSize.LowPart = GetFileSize(hInputFile, &FileSize.HighPart);

 nRecord = FileSize.QuadPart / REC_SIZE;

 if ((FileSize.QuadPart % REC_SIZE) != 0) nRecord++;

 CurPosIn.QuadPart = 0;

 for (ic = 0; ic < MAX_OVRLP; ic++) {

  /* Создать события чтения и записи для каждой структуры OVERLAPPED.*/

  hEvents[0][ic] = OverLapIn[ic].hEvent /* Событие чтения.*/

   = CreateEvent(NULL, TRUE, FALSE, NULL);

  hEvents[1][ic] = OverLapOut[ic].hEvent /* Событие записи. */

   = CreateEvent(NULL, TRUE, FALSE, NULL);

  /* Начальные позиции в файле для каждой структуры OVERLAPPED. */

  OverLapIn[ic].Offset = CurPosIn.LowPart;

  OverLapIn[ic].OffsetHigh = CurPosIn.HighPart;

  /* Инициировать перекрывающуюся операцию чтения для данной структуры OVERLAPPED. */

  if (CurPosIn.QuadPart < FileSize.QuadPart) ReadFile(hInputFile, AsRec[ic], REC_SIZE, &nin[ic], &OverLapIn[ic]); 

  CurPosIn.QuadPart += (LONGLONG)REC_SIZE;

 }

 /* Выполняются все операции чтения. Ожидать завершения события и сразу же сбросить его. События чтения и записи хранятся в массиве событий рядом друг с другом. */

 iWaits =0; /* Количество выполненных к данному моменту операций ввода/вывода. */

 while (iWaits < 2 * nRecord) {

  ic = WaitForMultipleObjects(2 * MAX_OVRLP, hEvents[0], FALSE, INFINITE) – WAIT_OBJECT_0;

  iWaits++; /* Инкрементировать счетчик выполненных операций ввода вывода.*/

  ResetEvent(hEvents[ic / MAX_OVRLP][ic % MAX_OVRLP]);

  if (ic < MAX_OVRLP) {

   /* Чтение завершено. */

   GetOverlappedResult(hInputFile, &OverLapIn[ic], &nin[ic], FALSE);

   /* Обработать запись и инициировать операцию записи. */

   CurPosIn.LowPart = OverLapIn[ic].Offset;

   CurPosIn.HighPart = OverLapIn[ic].OffsetHigh;

   CurPosOut.QuadPart = (CurPosIn.QuadPart / REC_SIZE) * UREC_SIZE;

   OverLapOut[ic].Offset = CurPosOut.LowPart;

   OverLapOut[ic].OffsetHigh = CurPosOut.HighPart;

   /* Преобразовать запись из ASCII в Unicode. */

   for (i =0; i < REC_SIZE; i++) UnRec[ic][i] = AsRec[ic][i];

   WriteFile(hOutputFile, UnRec[ic], nin[ic] * 2, &nout[ic], &OverLapOut[ic]);

   /* Подготовиться к очередному чтению, которое будет инициировано после того, как завершится начатая выше операция записи. */

   CurPosIn.QuadPart += REC_SIZE * (LONGLONG)(MAX_OVRLP);

   OverLapIn[ic].Offset = CurPosIn.LowPart;

   OverLapIn[ic].OffsetHigh = CurPosIn.HighPart;

  } else if (ic < 2 * MAX_OVRLP) { /* Операция записи завершилась. */

   /* Начать чтение. */

   ic –= MAX_OVRLP; /* Установить индекс выходного буфера. */

   if (!GetOverlappedResult (hOutputFile, &OverLapOut[ic], &nout[ic], FALSE)) ReportError(_T("Ошибка чтения."), 0, TRUE);

   CurPosIn.LowPart = OverLapIn[ic].Offset;

   CurPosIn.HighPart = OverLapIn[ic].OffsetHigh;

   if (CurPosIn.QuadPart < FileSize.QuadPart) {

    /* Начать новую операцию чтения. */

    ReadFile(hInputFile, AsRec[ic], REC_SIZE, &nin[ic], &OverLapIn[ic]);

   }

  }

 } 

 /* Закрыть все события. */

 for (ic = 0; ic < MAX_OVRLP; ic++) {

  CloseHandle(hEvents[0][ic]);

  CloseHandle(hEvents[1][ic]);

 }

 CloseHandle(hInputFile);

 CloseHandle(hOutputFile);

 return 0;

} 

Программа 14.1 способна работать только под управлением Windows NT. Средства асинхронного ввода/вывода Windows 9x не позволяют использовать дисковые файлы. В приложении В приведены результаты и комментарии, свидетельствующие о сравнительно низкой производительности программы atouOV. Как показали эксперименты, для достижения приемлемой производительности размер буфера должен составлять, по крайней мере, 32 Кбайт, но даже и в этом случае обычный синхронный ввод/вывод работает быстрее. К тому же, производительность этой программы не повышается и в условиях SMP, поскольку в данном примере, в котором обрабатываются всего лишь два файла, ЦП не является критическим ресурсом.

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

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

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

5.2. Перенаправление ввода/вывода

Из книги Linux-сервер своими руками автора Колисниченко Денис Николаевич

5.2. Перенаправление ввода/вывода Практически все операционные системы обладают механизмом перенаправления ввода/вывода, и Linux не является исключением из этого правила. Обычно программы вводят текстовые данные с консоли (терминала) и выводят данные на консоль. При вводе


Система ввода-вывода

Из книги Основы AS/400 автора Солтис Фрэнк

Система ввода-вывода Ввод-вывод — это Родни Дэнжерфилд[ 76 ] (Rodney Dangerfield) вычислительных систем: на него никто не обращает внимания. Всеобщий любимчик — процессор, а подсистема ввода-вывода рядом с ним — падчерица. Вот пример: когда надо охарактеризовать производительность


Операции ввода-вывода в AS/400

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

Операции ввода-вывода в AS/400 Теперь от аппаратной архитектуры ввода-вывода AS/400 перейдем к совместной работе OS/400, SLIC и аппаратуры при выполнении операции ввода-вывода для прикладной программы. Сначала рассмотрим объекты, поддерживающие ввод-вывод, затем — многоуровневую


Компоненты ввода-вывода

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

Компоненты ввода-вывода 4 Денис! Эту сноску — на поля! Таблица по старому изданию, сравнить с новым. Для верстальщика: по-моему, стоит убрать рамку — будет красивееТаблица 10.1. Язык ввода-вывода AMQ Очередь свободных сообщений BCT Таблица управления шиной BCU Устройство


Пример: копирование нескольких файлов на стандартное устройство вывода

Из книги Язык Си - руководство для начинающих автора Прата Стивен

Пример: копирование нескольких файлов на стандартное устройство вывода В программе 2.3 иллюстрируется использование стандартных устройств ввода/вывода, а также демонстрируется, как улучшить контроль ошибок и усовершенствовать взаимодействие с пользователем. Эта


Пример: последовательная обработка файлов с использованием метода отображения

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

Пример: последовательная обработка файлов с использованием метода отображения Программа atou (программа 2.4) иллюстрирует последовательную обработку файлов на примере преобразования ASCII-файлов к кодировке Unicode, приводящего к удвоению размера файла. Этот случай является


Следствия применения перекрывающегося ввода/вывода

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

Следствия применения перекрывающегося ввода/вывода Перекрывающийся ввод/вывод выполняется в асинхронном режиме. Это имеет несколько следствий.• Операции перекрывающегося ввода/вывода не блокируются. Функции ReadFile, WriteFile, TransactNamedPipe и ConnectNamedPipe осуществляют возврат, не


Состояния перекрывающегося ввода/вывода

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

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


Отмена выполнения операций перекрывающегося ввода/вывода

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

Отмена выполнения операций перекрывающегося ввода/вывода Булевская функция CancelIO позволяет отменить выполнение незавершенных операций перекрывающегося ввода/вывода, связанных с указанным дескриптором (у этой функции имеется всего лишь один параметр). Отменяется


Пример: преобразование файла с использованием расширенного ввода/вывода

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

Пример: преобразование файла с использованием расширенного ввода/вывода Программа 14.3 (atouEX) представляет собой переработанную версию программы 14.1. Эти программы иллюстрируют различие между двумя методами асинхронного ввода/вывода. Программа atouEx аналогична программе


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

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

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


Устройство ввода-вывода

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

Устройство ввода-вывода Вообще говоря, существует много способов ведения диалога человека с ЭВМ, но мы будем предполагать, что вы вводите команды при помощи клавиатуры и читаете ответ на экране


Процедуры ввода и вывода

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

Процедуры ввода и вывода Стандартная библиотека ввода-вывода языка C подключается с помощью директивы препроцессора #include <stdio. h>Форматный ввод данных пользователя с клавиатуры производится функцией scanf ().scanf (CONTROL, ARG1, ARG2, …);Данная функция осуществляет чтение