Асинхронне зчитування з файлу
Курсовий проект з дисципліни
«Системне програмування та операційні системи»
Виконав
студент гр. КС-31 В.С. Посухов
Керівник
ст. викл. А.М. Горбань
Оцінка ____________
Харків 2010
Содержание
Введение. 3
Аналитический обзор. 4
Выполнение проекта. 7
Алгоритм.. 7
Реализация функциональности. 7
Тестовые испытания. 13
Заключение. 14
Литература. 15
ПРИЛОЖЕНИЕ А.. 16
ПРИЛОЖЕНИЕ Б. 17
ПРИЛОЖЕНИЕ В.. 18
Введение
Целью данного курсового проекта является ознакомление с механизмом асинхронного ввода-вывода и функциями API для работы с событиями (events) ОС семейства Windows, разработка и написание программы, для множественного асинхронного чтения данных из файла с использованием дескриптора и событий. Задачей курсового проекта определен произвольный язык реализации программы, в данном случае С/C++, а также операционная система семейства Windows, в которой должна функционировать программа.
Существует два типа операций ввода/вывода - синхронный и асинхронный типы. Используя функции синхронного ввода/вывода, вы будете ждать, пока операция ввода/вывода не будет закончена. Функции асинхронного ввода/вывода позволяют вам посылать запросы на выполнение операции ввода/вывода системе и немедленно продолжить выполнение кода. Когда же операция асинхронного ввода/вывода будет закончена, система пошлет соответствующее уведомление.
Эта принципиально новая возможность введена впервые в Win32 с появлением реальной многозадачности. Т.к. вызывая функции чтения и записи данных синхронно, мы на самом деле передаем исходные данные одному из потоков (threads) операционной системы, который и осуществляет фактические обязанности по работе с устройством. Время доступа всех периферийных устройств гораздо больше доступа к ОЗУ, и программа, вызвавшая Read или write, будет дожидаться окончания операции ввода/вывода. Замедление работы программы налицо.
|
Выход был найден в использовании отложенного (overlapped) ввода/вывода. До начала отложенного ввода/вывода инициализируется дескриптор объекта типа события (функция createEvent) и структура типа OVERLAPPED. Вы вызываете функцию ReadFile или writeFile, в которой последним параметром указываете на OVERLAPPED. Эта структура содержит дескриптор события Windows (event).
ОС начинает операцию (ее выполняет отдельный программный поток, скрытый от программиста) и немедленно возвращает управление; мы можем не тратить время на ожидание. Признак того, что операция началась и продолжается — получение кода возврата ERROR_IO_PENDING. Если операция продолжается долго (например, чтение и запись файлов на дискете), то программа может спокойно выполнять последующие операторы. Событие будет установлено ОС тогда, когда ввод/вывод закончится.
Подробная информация о механизме асинхронного ввода-вывода представлена в разделе «Аналитический обзор». В этом разделе также приведен прототип функции, используемой для асинхронного чтения данных из файла.
Раздел «Выполнение проекта» содержит функциональные фрагменты кода программы с необходимыми комментариями (указание назначения основных и служебных функций, параметров, возвращаемых значений).
Для подтверждения функциональности интерфейса в указанном разделе представлен тестовый пример работы с реализованными функциями.
|
Аналитический обзор
Основы асинхронного ввода-вывода
По сравнению с другими операции ввода-вывода — одни из самых медленных и непредсказуемых. Центральный процессор выполняет арифметические вычисления и даже перерисовывает экран гораздо быстрее, чем считывает или записывает данные в файл или обменивается ими по сети. Асинхронный ввод- вывод позволяет эффективнее задействовать ресурсы и, таким образом, создавать более эффективные приложения.
Рассмотрим поток, выдающий запрос асинхронного ввода-вывода на устройство. Этот запрос передается драйверу устройства, который отвечает за выполнение собственно ввода-вывода. Пока драйвер ожидает ответа от устройства, поток приложения не приостанавливается в ожидании совершения запроса ввода, а продолжает работу и выполняет другие задачи.
В какой-то момент драйвер устройства завершает выполнение поставленного в очередь запроса и должен сообщить приложению, что данные отосланы, приняты или произошла ошибка. О том, как драйвер устройства уведомляет о завершении ввода-вывода, вы узнаете из следующего раздела. А сейчас посмотрим, как обслуживается очередь запросов асинхронного ввода-вывода. Обслуживание очередей запросов асинхронного ввода-вывода — важнейший вопрос при разработке высокопроизводительных масштабируемых приложений.
Чтобы получить асинхронный доступ к устройству, нужно вызвать функцию CreateFile с установленным в параметре dwFlagsAndAttrs флагом FILE_FIAG_OVERLAPPED, который уведомляет систему о вашем намерении получить асинхронный доступ к устройству.
|
Чтобы поставить запрос ввода-вывода в очередь драйвера устройства, используются функции ReadFile и WriteFile. Их прототипы выглядят следующия образом:
BOOL ReadFile(
HANDLE hFile, // дескриптор файла
LPVOID lpBuffer, // буфер данных
DWORD nNumberOfBytesToRead, // число байтов для чтения
LPDWORD lpNumberOfBytesRead, // число прочитанных байтов
LPOVERLAPPED lpOverlapped // асинхронный буфер
);
Параметры
hFile
[in] Дескриптор файла, который читается. Дескриптор файла должен быть, создан с правом доступа GENERIC_READ.
Windows NT/2000/XP: Для асинхронных операций чтения, параметр hFile может быть любым дескриптором открытым с флажком FILE_FLAG_OVERLAPPED функцией CreateFile или дескриптор сокета, возвращенный функцией socket или accept.
lpBuffer
[out] Указатель на буфер, который принимает прочитанные данные.
nNumberOfBytesToRead
[in] Число байтов, которые читаются из файла.
lpNumberOfBytesRead
[out] Указатель на переменную, которая получает число прочитанных байтов. Функция ReadFile устанавливает это значение в нуль перед началом любой работы или проверкой ошибок.
Windows NT/2000/XP: Если параметр lpOverlapped имеет значение ПУСТО (NULL), параметр lpNumberOfBytesRead не может быть значением ПУСТО (NULL). Если lpOverlapped имеет - значение не ПУСТО (NULL), lpNumberOfBytesRead может быть значением ПУСТО (NULL). Если это - асинхронная операция чтения, Вы можете получить число прочитанных байтов при помощи вызова функции GetOverlappedResult.
lpOverlapped
[in] Указатель на структуру OVERLAPPED. Эта структура требуется тогда, если параметр hFile создавался с флажком FILE_FLAG_OVERLAPPED.
Если hFile был открыт с флажком FILE_FLAG_OVERLAPPED, у параметра lpOverlapped не должно быть значения ПУСТО (NULL). Он должен указать на правильную структуру OVERLAPPED. Если hFile создавался с флажком FILE_FLAG_OVERLAPPED, а lpOverlapped имеет значение ПУСТО (NULL), функция может неправильно сообщить о завершении операций чтения.
При вызове обе эти функции проверяют, открыто ли устройство, определяемое параметром hfile с флагом FILE_FLAG_OVERLAPPED. Если флаг установлен, функции выполняют асинхронный ввод-вывод. Между прочим, вызывая любую из этих функций для асинхронного ввода-вывода, можно (обычно так и делают) устанавливать параметр lpNumberOfBytesRead в NULL. В конце концов мы ведь ожидаем, что эти функции вернет управление до того, как выполнится запрос ввода-вывода, — какой смысл рассматривать число переданных байтов после возврата из этой функции!
Структура OVERLAPPED
При выполнении асинхронного ввода-вывода параметр pOverlapped должен содержать адрес проинициализированной структуры OVERLAPPED. Такое название («overlapped» — перекрывающийся, накладывающийся) она получила поскольку выполнение запроса ввода-вывода совпадает по времени с выполнением других задач потоком вашего приложения. Эта структура выглядит так:
typedef struct _OVERLAPPED {
ULONG_PTR Internal;
ULONG_PTR InternalHigh;
DWORD Offset;
DWORD OffsetHigh;
HANDLE hEvent;
} OVERLAPPED;
Параметры
Internal
Зарезервирован для использования операционной системой. Этот член структуры, который определяет системно-зависимое состояние, правильный тогда, когда функция GetOverlappedResult возвращает значение ERROR_IO_PENDING без установки дополнительной информации об ошибке.
InternalHigh
Зарезервирован для использования операционной системой. Этот член структуры, который устанавливает длину переданных данных, правильный тогда, когда функция GetOverlappedResult возвращений значение ИСТИНА (TRUE).
Offset
Местоположение файла, в котором начинается передача. Позиция файла - это смещение байта от начала файла. Вызывающий процесс должен установить этот член структуры перед вызовом функции WriteFile или ReadFile.
Этот член структуры используется только тогда, когда устройство - файл. В противном случае, этот член структуры должен быть нуль.
OffsetHigh
Старшее слово позиции файла, в который начинается передача.
Этот член структуры используется только тогда, когда устройство - файл. В противном случае, этот член структуры должен быть нуль.
hEvent
Дескриптор события, которые должно быть установлено в сигнальное состояние, когда операция завершилась. Вызывающий процесс должен установить в этом члене структуры или нуль, или допустимый дескриптор события перед вызовом любых перекрывающих функций. Чтобы создать объект события, используйте функцию CreateEvent. Эта функция возвращает дескриптор, который может быть использован, чтобы синхронизировать одновременные запросы ввода - вывода (I/O) к устройству.
Функции типа ReadFile и WriteFile устанавливают этот дескриптор в несигнальное состояние прежде, чем они начинают операцию ввода-вывода (I/O). Когда операция завершается, дескриптор устанавливается в сигнальное состояние.
Функции типа GetOverlappedResult и функции ожидания сбрасывают автосброс событий в несигнальное состояние. Поэтому, если Вы используете автосброс события, ваше приложение может зависнуть, если Вы ожидаете операцию завершения, чтобы затем вызвать функцию GetOverlappedResult. [1]
Выполнение проекта
Алгоритм
Для реализации поставленной задачи в моей программе запускается на выполнение 5 потоков: один главный, 2 из них читают данные асинхронно с использованием функции ReadFile, 2 из них следят за завершением чтения с файла. Если поток чтения был запущен удачно, то глобальная переменная, подсчитывающая количество работающих потоков, увеличивается на 1. После завершения читающего потока выдается сообщение о завершении работы потока. Как только завершилось чтение данных из файла, то устанавливается событие в структуре OVERLAPPED, которое перехватывает «монитор» этого события с помощью функции WaitForSingleObject, и переменная количеств работающих потоков уменьшается соответственно на 1. Программа работает, пока хотя бы один поток работает.