Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

Отображение файлов в оперативную память




Отображение файлов в оперативную память впервые появилось в BSD Unix. Идея такого отображения появилась как результат осмысливания избыточности действий при файловом вводе и выводе в операционной системе, использующей виртуальную память. Действительно, при вводе и выводе происходит пересылка данных между внешней памятью, хранящей файл, и служебными областями ОС (буферами ввода-вывода внутри адресного пространства ОС), и тут же неизбежная пересылка данных между буферами ОС и буферами данных прикладного процесса. Заметим, что использование системой ввода-вывода непосредственно пользовательских буферов оказалось бы нарушением правил защиты памяти с вытекающими отсюда неприятностями для функционирования системы. А двукратная пересылка данных заметно снижает быстродействие системы при работе с файлами.

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

Использование в программах Unix файлов, которые отображаются в память, требует заголовочного файла mman.h, расположенного в подкаталоге sys стандартного каталога для заголовочных файлов, так что его подключение выполняется директивой

#include <sys/mman.h>

Для использования рассматриваемого отображения в Unix служит системная функция с прототипом

void* mmap(void* addr, size_t size, int prot, int flag, int fd, off_t pos),

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

Аргумент size определяет размер отображаемой области файла. Если его значение не кратно размеру страницы, то size байтов будут взяты из файла, а оставшаяся часть страницы заполнена нулями. Аргумент pos задает начальную позицию в файле, с которой начинается отображение, что дает возможность отображать не только весь файл, но и любой его последовательный участок. Параметр pos должен быть кратен размеру страницы.

Аргумент prot задает права доступа к отображаемой памяти и может представляться одной из следующих символьных констант: PROT_READ, PROT_WRITE и PROT_EXEC. Аргумент флагов flag задает опции отображения и может представляться одной из констант MAP_SHARED, MAP_PRIVATE, MAP_FIXED. Последняя из них задает обязательность точного использования аргумента addr и возвращение ошибки при невозможности выполнить это указание. Константы MAP_SHARED и MAP_PRIVATE задают соответственно разделяемое несколькими процессами и сугубо индивидуальное использование области отображения файла в виртуальную память. Кроме того, следует иметь в виду, что при указании флага MAP_PRIVATE изменения в виртуальной области отображения файла не только не видны в других процессах, но и не записываются в файл (содержимое отображения файла используется как временный файл для текущего процесса). При флаге же MAP_SHARED все изменения в области отображения файла, представляющей его содержимое, тут же становятся видны другим процессам, открывшим этот же файл, а изменения в этой области записываются в файл на диске.

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

int munmap(void* addr, size_t size).

Если при создании отображения был указан флаг MAP_SHARED, то в файл вносятся все оставшиеся изменения, при флаге MAP_PRIVATE все изменения отбрасываются. Следует иметь в виду, что функция munmap только отменяет отображение файла, но не закрывает файл, который требуется закрыть обычным вызовом close().

Следующий пример, приведенный программой в листинге 10.5.1, демонстрирует использование отображения файлов в память. В этой программе выполняется быстрое копирование файла, имя которого задано аргументом командной строки. Файл результирующей копии назван для упрощения задачи именем mytemp.

 

#include <stdio.h>

#include <sys/mman.h>

#include <fcntl.h>

 

void main(int argc, char **argv)

{ int hin, hout;

size_t fsize;

void *source, *target;

 

if (argc<2) {printf("Error format call program!\n"); exit(1);}

hin=open(argv[1],O_RDONLY);

if (hin = = -1) {printf("Error open input file\n"); exit(2);}

hout=open("mytemp",O_RDWR | O_CREAT | O_TRUNC, 0644);

if (hout = = -1) {printf("Error open output file\n"); exit(3);}

fsize = lseek(hin, 0, SEEK_END);

lseek(hout, fsize-1,SEEK_SET);

write(hout,"!",1);

source=mmap(0, fsize, PROT_READ, MAP_SHARED, hin,0);

if (source = = (void*)-1) {printf("Error map input file\n"); exit(4);}

target=mmap(0, fsize, PROT_WRITE, MAP_SHARED, hout,0);

if (target = = (void*)-1) {printf("Error map output file\n"); exit(5);}

memcpy(target, source, fsize);

munmap(source, fsize); munmap(target, fsize);

close(hin); close(hout);

}

Листинг 10.5.1. Использование отображения файлов

для быстрого копирования в Unix

 

В этой программе, чтобы правильно построить область отображения еще не существующего выходного файла, создается его фиктивное содержимое путем записи некоторого символа (выбран символ '!', но это не обязательно) в последнюю позицию файла исходя из предположения о его действительном размере. В противном случае при выполнении оператора target=mmap(...,hout,0) будет создана пустая виртуальная область памяти с последующими неприятностями для дальнейшего выполнения программы.

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

В операционной системе Windows для отображения в память файлов используются уже частично рассмотренные в разделе 10.4 функции CreateFileMapping, MapViewOfFile и UnmapViewOfFile. Для отображения собственно файлов первый аргумент функции CreateFileMapping должен задаваться хэндлом предварительно открытого файла, третий аргумент этой функции protect по своим значениям должен соответствовать режиму использования файла, заданному при открытии последнего. (Если используется константа PAGE_READONLY, то файл должен быть открыт с доступом GENERIC_READ, а если используется константа PAGE_READWRITE, то при открытии файла должен был быть указан доступ константами GENERIC_READ и GENERIC_WRITE.) Напомним еще раз, что в Windows функция CreateFileMapping практически создает только область виртуальных адресов, подготовленную для последующего отображения. (Кроме того, ею создается объект ядра, который и служит информационной структурой дальнейшего управления и контроля за отображаемым объектом.) Собственно отображение (в отличие от Unix) здесь выполняется вызовом системной функции MapViewOfFile.

Эта последняя функция для файла должна задавать тот же режим доступа, что и указывалось на предыдущем этапе (присутствует заметная избыточность, не характерная для большинства профессиональных решений в области системного программирования, но характерная для продукции Microsoft). Практически две последние функции Windows выполняют в совокупности ту же работу, что делает в Unix единственная функция mmap. Единственным существенным отличием является возможность явного задания размера области отображения предпоследними параметрами функции CreateFileMapping. (Напомним, что эта же функция в Windows системах применяется и для побочных целей – первого этапа построения разделяемой памяти.)

После завершения работы в Windows с отображаемым в память файлом следует выполнить вызов функции UnmapViewOfFile для базового адреса области отображения и закрыть хэндл, полученный от функции CreateFileMapping. Кроме того, не следует забывать и закрывать файл, открытый для отображения.

Следующий пример, приведенный программой в листинге 10.5.2, демонстрирует решение в Windows той же задачи, что уже рассматривалась для Unix.

 

#include <windows.h>

#include <stdio.h>

void main(int argc, char **argv)

{ HANDLE hin, hout;

int fsize;

void *source, *target;

HANDLE hsource, htarget;

DWORD actlen;

 

if (argc<2) {printf("Error format call program!\n"); exit(1);}

hin=CreateFile(argv[1], GENERIC_READ,

FILE_SHARE_READ, 0, OPEN_EXISTING,

FILE_ATTRIBUTE_NORMAL, 0);

if (hin = = INVALID_HANDLE_VALUE)

{printf("Error open input file\n"); exit(2);}

hout=CreateFile("mytemp", GENERIC_READ

|GENERIC_WRITE, FILE_SHARE_READ, 0,

CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);

if (hout = = INVALID_HANDLE_VALUE)

{printf("Error open output file\n"); exit(3);}

fsize=SetFilePointer(hin, 0, 0, FILE_END);

hsource=CreateFileMapping(hin,NULL,PAGE_READONLY,0,0,NULL);

if (hsource = = NULL) {printf("Error CreateMap input file\n");

exit(4);}

source=MapViewOfFile(hsource, FILE_MAP_READ,0,0,0);

if (source = = NULL)

{printf("Error map input file\n"); exit(4);}

htarget=CreateFileMapping(hout,NULL,PAGE_READWRITE,0,fsize,NULL);

if (htarget = = NULL)

{printf("Error CreateMap output file\n"); exit(5);}

target=MapViewOfFile(htarget, FILE_MAP_WRITE,0,0,0);

if (target = = NULL) {printf("Error map output file\n"); exit(5);}

memcpy(target, source, fsize);

UnmapViewOfFile(source); UnmapViewOfFile(target);

CloseHandle(hin); CloseHandle(hout);

CloseHandle(hsource); CloseHandle(htarget);

}

Листинг 10.5.2. Использование отображения файлов

для быстрого копирования в Windows

 

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




Поделиться с друзьями:


Дата добавления: 2014-01-05; Просмотров: 1346; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.01 сек.