- •1. Проецируемые в память файлы
- •2. Проецирование в память exe- и dll-файлов
- •2.1. Статические данные разделяются несколькими экземплярами exe или dll
- •2.2. Использование общего раздела в приложениях для межпроцессного взаимодействия
- •3. Использование проецируемых в память файлов
- •3.1. Создание/открытие объекта ядра «файл»
- •3.2. Создание объекта ядра – «проекция файла»
- •3.3. Проецирование файловых данных на адресное пространство процесса
- •3.5. Закрытие объектов «проекция файла» и «файл»
- •3.4. Отключение файла данных от адресного пространства процесса
- •4. Файлы, проецируемые на физическую память из страничного файла
- •5. Порядок выполнения работы
- •6. Контрольные вопросы
3.4. Отключение файла данных от адресного пространства процесса
Когда необходимость в данных файла (спроецированного на регион адресного пространства процесса) отпадет, необходимо освободить регион вызовом:
BOOL UnmapViewOfFile(PVOID pvBaseAddress);
Ее единственный параметр, pvBaseAddress, указывает базовый адрес возвращаемо го системе региона. Он должен совпадать со значением, полученным после вызова MapViewOfFile.. Если вызывать функцию UnmapViewOfFile, регион не освободится до завершения процесса. Повторный вызов MapViewOfFile приводит к резервированию нового региона в пределах адресного пространства процесса, но ранее выделенные регионы не освобождаются.
Для повышения производительности при работе с представлением файла система буферизует страницы данных в файле и не обновляет немедленно дисковый образ файла. При необходимости можно заставить систему записать измененные данные (все или частично) в дисковый образ файла, вызвав функцию FlushViewOfFile.
BOOL FlushViewOfFile(PVOID pvAddress, SIZE_T dwNumberOfBytesToFlush);
Ее первый параметр принимает адрес байта, который содержится в границах представления файла, проецируемого в память. Переданный адрес округляется до значения, кратного размеру страниц. Второй параметр определяет количество байтов, которые надо записать в дисковый образ файла. Если FlushViewOfFile вызывается в отсутствие измененных данных, она просто возвращает управление.
В случае проецируемых файлов, физическая память которых расположена на сетевом диске, FlushViewOfFile гарантирует, что файловые данные будут перекачаны с рабочей станции. Но она не гарантирует, что сервер, обеспечивающий доступ к этому файлу, запишет данные на удаленный диск, так как он может просто кэшировать их. Для подстраховки при создании объекта «проекция файла» и последующем проецировании его представления можно использовать флаг FILE_FLAG_WRITE_THROUGH. При открытии файла с этим флагом функция FlushViewOfFile вернет управление только после сохранения на диске сервера всех файловых данных.
У функции UnmapViewOfFile есть одна особенность. Если первоначально представление было спроецировано с флагом FILE_MAP_COPY, любые изменения, внесенные в файловые данные, на самом деле производятся над копией этих данных, хранящихся в страничном файле. Вызванной в этом случае функции UnmapViewOfFile нечего обновлять в дисковом файле, и она просто инициирует возврат системе страниц физической памяти, выделенных из страничного файла. Все изменения в данных на этих страницах теряются. Windows 98 не поддерживает атрибут защиты «копирование при записи», поэтому при просмотре первого представления файла, проецируемого в память, невозможно проверить страницы по флагу PAGE_READWRITE.
3.5. Закрытие объектов «проекция файла» и «файл»
Закончив работу с любым открытым объектом ядра, необходимо его закрыть, иначе в процессе начнется утечка ресурсов. Конечно, по завершении процесса система автоматически закроет объекты, оставленные открытыми. Но, если процесс поработает еще какое-то время, может накопиться слишком много незакрытых описателей. Поэтому следует писать код так, чтобы открытые объекты всегда закрывались, как только они станут не нужны. Для закрытия объектов «проекция файла» и «файл» дважды вызывается функция CloseHandle. Рассмотрим это подробнее на фрагменте псевдокода.
HANDLE hFile = CreateFile(...); HANDLE hFileMapping = CreateFileMapping(hFile,...); PVOID pvFile = MapViewOfFile(hFileMapping,.. );
// работаем с файлом, спроецированным в память UnmapViewOfFile(pvFile);
CloseHandle(hFileMapping); CloseHandle(hFile);
Этот фрагмент иллюстрирует стандартный метод управления проецируемыми файлами. Но он не отражает того факта, что при вызове MapViewOfFile система увеличивает счетчики числа пользователей и объектов «файл» и «проекция файла». Этот побочный эффект весьма важен, так как позволяет переписать показанный выше фрагмент кода следующим образом:
HANDLE hFile = CreateFile(..); HANDLE hFileMapping = CreateFileMapping(hFile,.. );
CloseHandle(hFile);
PVOID pvFile = MapViewOfFile(hFileMapping,...);
CloseHandle(hFileMapping);
// работаем с файлом, спроецированным в память UnmapViewOfFile(pvFile);
При операциях с проецируемыми файлами обычно открывают файл, создают объект «проекция файла» и с его помощью проецируют представление файловых данных на адресное пространство процесса. Поскольку система увеличивает внутренние счетчики объектов «файл» и «проекция файла», их можно закрыть в начале кода, тем самым, исключив возможную утечку ресурсов.
Если создавать из одного файла несколько объектов «проекция файла» или проецировать несколько представлений этого объекта, применить функцию CloseHandle в начале кода не удается — описатели еще понадобятся для дополнительных вызовов CreateFileMapping и MapViewOfFile.
