UNIX: взаимодействие процессов
Шрифт:
2. Со специальными файлами для обеспечения неименованного отображения памяти (разделы 12.4 и 12.5).
3. С shm_open для создания участка разделяемой неродственными процессами памяти Posix.
Аргумент addr может указывать начальный адрес участка памяти процесса,
Аргумент len задает длину отображаемого участка в байтах; участок может начинаться не с начала файла (или другого объекта), а с некоторого места, задаваемого аргументом offset. Обычно offset = 0. На рис. 12.5 изображена схема отображения объекта в память.
Рис. 12.5. Пример отображения файла в память
Защита участка памяти с отображенным объектом обеспечивается с помощью аргумента prot и констант, приведенных в табл. 12.1. Обычное значение этого аргумента — PROT_READ | PROT_WRITE, что обеспечивает доступ на чтение и запись.
Таблица 12.1. Аргумент prot для вызова mmap
prot | Описание |
---|---|
PROT_READ | Данные могут быть считаны |
PROT_WRITE | Данные могут быть записаны |
PROT_EXEC | Данные могут быть выполнены |
PROT_NONE | Доступ к данным закрыт |
Таблица 12.2. Аргумент flag для вызова mmap
flag | Описание |
---|---|
MAP SHARED | Изменения передаются другим процессам |
MAP_PRIVATE | Изменения не передаются другим процессам и не влияют на отображенный объект |
MAP_FIXED | Аргумент addr интерпретируется как адрес памяти |
Аргумент flags может принимать значения из табл. 12.2. Можно указать только один из флагов — MAP_SHARED или MAP_PRIVATE, прибавив к нему при необходимости MAP_FIXED. Если указан флаг MAP_PRIVATE, все изменения будут производиться только с образом объекта в адресном пространстве процесса; другим процессам они доступны не будут. Если же указан флаг MAP_SHARED, изменения отображаемых данных видны всем процессам, совместно использующим объект.
Для обеспечения переносимости пpoгрaмм флаг MAP_FIXED указывать не следует. Если он не указан, но аргумент addr представляет собой ненулевой указатель, интерпретация этого аргумента зависит от реализации. Ненулевое значение addr обычно трактуется как указатель на желаемую область памяти, в которую нужно произвести отображение. В переносимой программе значение addr должно быть нулевым и флаг MAP_FIXED не должен быть указан.
Одним из способов добиться совместного использования памяти родительским и дочерним процессами является вызов mmap с флагом MAP_SHARED перед вызовом fork. Стандарт Posix.1 гарантирует в этом случае, что все отображения памяти, установленные родительским процессом, будут унаследованы дочерним. Более того, изменения в содержимом объекта, вносимые родительским процессом, будут видны дочернему, и наоборот. Эту схему мы вскоре продемонстрируем в действии.
Для отключения отображения объекта в адресное пространство процесса используется
вызов munmap:Аргумент addr должен содержать адрес, возвращенный mmap, a len — длину области отображения. После вызова munmap любые попытки обратиться к этой области памяти приведут к отправке процессу сигнала SIGSEGV (предполагается, что эта область памяти не будет снова отображена вызовом mmap).
Если область была отображена с флагом MAP_PRIVATE, все внесенные за время работы процесса изменения сбрасываются.
В изображенной на рис. 12.5 схеме ядро обеспечивает синхронизацию содержимого файла, отображенного в память, с самой памятью при помощи алгоритма работы с виртуальной памятью (если сегмент был отображен с флагом MAP_SHARED). Если мы изменяем содержимое ячейки памяти, в которую отображен файл, через некоторое время содержимое файла будет соответствующим образом изменено ядром. Однако в некоторых случаях нам нужно, чтобы содержимое файла всегда было в соответствии с содержимым памяти. Тогда для осуществления моментальной синхронизации мы вызываем msync:
Аргумент flags представляет собой комбинацию констант из табл. 12.3.
Таблица 12.3. Значения аргумента flags для функции msync
Константа | Описание |
---|---|
MS_ASYNC | Осуществлять асинхронную запись |
MS_SYNC | Осуществлять синхронную запись |
MS_INVALIDATE | Сбросить кэш |
Из двух констант MS_ASYNC и MS_SYNC указать нужно одну и только одну. Отличие между ними в том, что возврат из функции при указании флага MS_ASYNC происходит сразу же, как только данные для записи будут помещены в очередь ядром, а при указании флага MS_SYNC возврат происходит только после завершения операций записи. Если указан и флаг MS_INVALIDATE, все копии файла, содержимое которых не совпадает с его текущим содержимым, считаются устаревшими. Последующие обращения к этим копиям приведут к считыванию данных из файла.
Почему вообще используется отображение в память?
До сих пор мы всегда говорили об отображении в память содержимого файла, который сначала открывается вызовом open, а затем отображается вызовом mmap. Удобство состоит в том, что все операции ввода-вывода осуществляются ядром и скрыты от программиста, а он просто пишет код, считывающий и записывающий данные в некоторую область памяти. Ему не приходится вызывать read, write или lseek. Часто это заметно упрощает код.
ПРИМЕЧАНИЕ
Вспомните нашу реализацию очередей сообщений Posix с использованием mmap, где значения сохранялись в структуре msg_hdr и считывались из нее же (листинги 5.26 и 5.28).
Следует, однако, иметь в виду, что не все файлы могут быть отображены в память. Попытка отобразить дескриптор, указывающий на терминал или сокет, приведет к возвращению ошибки при вызове mmap. К дескрипторам этих типов доступ осуществляется только с помощью read и write (и аналогичных вызовов).
Другой целью использования mmap может являться разделение памяти между неродственными процессами. В этом случае содержимое файла становится начальным содержимым разделяемой памяти и любые изменения, вносимые в нее процессами, копируются обратно в файл (что дает этому виду IPC живучесть файловой системы). Предполагается, что при вызове mmap указывается флаг MAP_SHARED, необходимый для разделения памяти между процессами.