Основы программирования в Linux
Вызов
также позволяет реализовать блокировку файла. См. более подробную информацию в разделе 2 интерактивного справочного руководства или главу 7, в которой мы обсуждаем блокировку файлов.fcntlmmap
Система UNIX предоставляет полезное средство, позволяющее программам совместно использовать память, и, к счастью, оно включено в версию 2.0 и более поздние версии ядра Linux. Функция
(для отображения памяти) задает сегмент памяти, который может читаться двумя или несколькими программами и в который они могут записывать данные. Изменения, сделанные одной программой, видны всем остальным.mmapВы можете применить то же самое средство для работы с файлами, заставив все содержимое файла на диске выглядеть как массив в памяти. Если файл состоит из записей, которые могут быть описаны структурами на языке С, вы сможете обновлять файл с помощью методов доступа к массиву структур.
Это становится возможным благодаря применению сегментов виртуальной памяти с набором особых прав доступа. Чтение из сегмента и запись в него заставляет операционную систему читать соответствующую часть файла на диске и писать данные в нее.
Функция mmap создает указатель на область памяти, ассоциированную с содержимым файла, доступ к которому осуществляется через открытый дескриптор файла.
<b>#include <sys/mman.h></b><b>void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off);</b>Изменить начальную позицию порции данных файла, к которым выполняется обращение через совместно используемый сегмент, можно, передавая параметр
. Открытый дескриптор файла задается в параметреoff. Объем данных, к которым возможен доступ (т. е. размер сегмента памяти), указывается в параметреfildes.lenПараметр
можно использовать для запроса конкретного адреса памяти. Если он равен нулю, результирующий указатель формируется автоматически. Последний вариант рекомендуется, потому что в противном случае трудно добиться переносимости; диапазоны доступных адресов в разных системах отличаются.addrПараметр
используется для установки прав доступа к сегменту памяти. Он представляет собой результат поразрядной операции or, примененной к следующим константам:prot□
— сегмент может читаться;PROT_READ□
— в сегмент можно писать;PROT_WRITE□
— сегмент может выполняться;PROT_EXEC□
— к сегменту нет доступа.PROT_NONEПараметр
контролирует, как изменения, сделанные программой в сегменте, отражаются в других местах; его возможные значения приведены в табл. 3.7.flagsТаблица 3.7
Константа Описание MAP_PRIVATEСегмент частный, изменения локальные MAP_SHAREDИзменения сегмента переносятся в файл MAP_FIXEDСегмент должен располагаться по заданному адресу addrФункция
вызывает запись изменений в части или во всем сегменте памяти обратно а отображенный файл (или считывание из файла).msync<b>#include <sys/mman.h></b><b>int msync(void *addr, size_t len, int flags);</b>Корректируемая часть сегмента задается передачей начального адреса
и размераaddr. Параметрlenуправляет способом выполнения корректировки с помощью вариантов, приведенных в табл. 3.8.flagsТаблица 3.8
Константа Описание MS_ASYNCВыполнять запись асинхронно MS_SYNCВыполнять запись синхронно MS_INVALIDATEОбновить другие отражения этого файла так, чтобы они содержали изменения, внесенные этим вызовом Функция
освобождает сегмент памяти.munmap<b>#include <sys/mman.h></b><b>int munmap(void *addr, size_t len);</b>В программе mmap.с из упражнения 3.5 показан файл из структур, которые будут корректироваться с помощью функции
и обращений в стиле массива. Ядро Linux версий, меньших 2.0, не полностью поддерживает применение функцииmmap. Программа работает корректно в системе Sun Solaris и других системах.mmapУпражнение 3.5. Применение функцииmmap1. Начните с определения структуры
и создайтеRECORDвариантов, в каждый из которых записывается собственный номер. Они будут добавлены в конец файла records.dat.NRECORDS#include <unistd.h>#include <stdio.h>#include <sys/mman.h>#include <fcntl.h>#include <stdlib.h>typedef struct {int integer;char string[24];} RECORD;#define NRECORDS (100)int main() {RECORD record, *mapped;int i, f;FILE *fp;fp = fopen("records.dat", "w+");for (i=0; i<NRECORDS; i++) {record.integer = i;sprintf(record.string, "RECORD-%d", i);fwrite(&record, sizeof(record), 1, fp);}fclose(fp);2. Далее измените целое значение записи с 43 на 143 и запишите его в строку 43-й записи.