В связи с данными недостатками в стандарт POSIX.1b был добавлен новый программный интерфейс для работы с разделяемой памятью, которому и посвящена данная глава.
Разделяемая память POSIX позволяет неродственным процессам иметь общий отображаемый участок без необходимости создавать соответствующий отображенный файл. Этот механизм поддерживается в ядре Linux, начиная с версии 2.4.
Стандарт SUSv3 не содержит никаких подробностей реализации разделяемой памяти POSIX. В частности, в нем отсутствуют требования к использованию файловой системы (реальной или виртуальной) для идентификации объектов разделяемой памяти, хотя многие UNIX-системы задействуют для этого средства файловой системы. В ряде систем имена таких объектов представляют собой файлы, хранящиеся в специальном каталоге в рамках стандартной файловой системы. Linux использует для этого файловую систему tmpfs (см. раздел 14.10), подключенную к каталогу /dev/shm. Она обладает сохраняемостью на уровне ядра; это значит, что объекты разделяемой памяти, которые в ней хранятся, существуют независимо от того, открыты ли они каким-либо процессом, но теряются при выключении системы.
Общий объем памяти на всех разделяемых участках в системе ограничен размером связанной с ними файловой системы tmpfs. Она обычно подключается во время загрузки и имеет некий стандартный размер (например, 256 Мбайт), который при необходимости может быть изменен администратором путем повторного подключения с помощью команды вида mount — o remount,size=<количество_байтов>.
Для использования объектов разделяемой памяти POSIX нужно выполнить два шага.
1. Воспользоваться функцией shm_open(), чтобы открыть объект с заданным именем (правила именования объектов разделяемой памяти POSIX описаны в разделе 47.1). Эта функция является аналогом системного вызова open(). Она либо создает новый объект разделяемой памяти, либо открывает уже существующий. В качестве результата shm_open() возвращает файловый дескриптор, ссылающийся на объект.
2. Передать файловый дескриптор, полученный на предыдущем шаге, в вызов mmap(), в аргументе flags которого указан флаг MAP_SHARED. Это отобразит объект разделяемой памяти на виртуальное адресное пространство процесса. По аналогии с другими способами применения вызова mmap() можно закрыть файловый дескриптор, не влияя на само отображение. Но иногда данный дескриптор лучше держать открытым, чтобы использовать его в последующих вызовах fstat() и ftruncate() (см. раздел 50.2).
Поскольку для обращения к объекту разделяемой памяти применяется файловый дескриптор, для работы с данным объектом не требуется специальных функций; вместо этого можно применять уже имеющиеся в UNIX системные вызовы (например, ftruncate()).
Функция shm_open() создает новый или открывает уже существующий объект разделяемой памяти. Ее аргументы аналогичны тем, которые используются в вызове open().
#include
#include
#include
int shm_open(const char *
Возвращает файловый дескриптор или -1, если произошла ошибка
Аргумент name идентифицирует объект разделяемой памяти, который нужно создать или открыть. Аргумент oflag — это битовая маска, влияющая на работу вызова. Поддерживаемые ею значения перечислены в табл. 50.1.
Таблица 50.1. Битовые значения для аргумента oflag функции shm_open()
Флаг — Описание
O_CREAT — Создает объект, если он не был создан ранее
O_EXCL — Выполняет исключительно создание объекта, если указан флаг O_CREAT
O_RDONLY — Открывает только для чтения
O_RDWR — Открывает только для записи
O_TRUNC — Усекает объект до нулевой длины
Одно из назначений аргумента oflag заключается в определении того, нужно ли создавать объект разделяемой памяти перед его открытием. Если этот аргумент не включает в себя флаг O_CREAT, то открывается уже существующий объект. В противном случае при отсутствии объекта с таким именем он будет создан. Совместное использование флагов O_EXCL и O_CREAT гарантирует, что создателем объекта будет вызывающий процесс; в случае существования объекта мы получим ошибку EEXIST.
Аргумент oflag также определяет, какой доступ будет у вызывающего процесса к объекту разделяемой памяти; для этого применяется одна из констант: O_RDONLY или O_RDWR.
Последнее значение, O_TRUNC, приводит к установке нулевой длины успешно открытому объекту.
В Linux усечение выполняется даже в случае, когда объект открыт только для чтения. Но в стандарте SUSv3 отмечается, что совместное использование флагов O_TRUNC и O_RDONLY приводит к неопределенным результатам, поэтому портируемые приложения не могут полагаться на такое поведение.