UNIX: взаимодействие процессов
Шрифт:
13.7. Резюме
Разделяемая память Posix реализуется с помощью функции mmap, обсуждавшейся в предыдущей главе. Сначала вызывается функция shm_open с именем объекта Posix IPC в качестве одного из аргументов. Эта функция возвращает дескриптор, который затем передается функции mmap. Результат аналогичен отображению файла в память, но разделяемая память Posix не обязательно реализуется через файл.
Поскольку доступ к объектам разделяемой памяти может быть получен через дескриптор, для установки размера объекта используется функция ftruncate, а информация о существующем объекте (биты разрешений, идентификаторы пользователя и группы, размер) возвращается
В главах, рассказывающих об очередях сообщений и семафорах Posix, мы приводили примеры их реализации через отображение в память (разделы 5.8 и 10.15). Для разделяемой памяти Posix мы этого делать не будем, поскольку реализация тривиальна. Если мы готовы использовать отображение в файл (что и сделано в Solaris и Digital Unix), shm_open реализуется через open, a shm_unlink — через unlink.
Упражнения
1. Измените программы из листингов 12.6 и 12.7 таким образом, чтобы они работали с разделяемой памятью Posix, а не с отображаемым в память файлом. Убедитесь, что результаты будут такими же, как и для отображаемого в память файла.
2. В циклах for в листингах 13.3 и 13.4 используется команда *ptr++ для перебора элементов массива. Не лучше ли было бы использовать ptr[i]?
ГЛАВА 14
Разделяемая память System V
14.1. Введение
Основные принципы разделяемой памяти System V совпадают с концепцией разделяемой памяти Posix. Вместо вызовов shm_open и mmap в этой системе используются вызовы shmget и shmat.
Для каждого сегмента разделяемой памяти ядро хранит нижеследующую структуру, определенную в заголовочном файле <sys/shm.h>:
Структура ipc_perm была описана в разделе 3.3; она содержит разрешения доступа к сегменту разделяемой памяти.
14.2. Функция shmget
С помощью функции shmget можно создать новый сегмент разделяемой памяти или подключиться к существующему:
Возвращаемое целочисленное значение называется идентификатором разделяемой памяти. Он используется с тремя другими функциями shmXXX.
Аргумент key может содержать значение, возвращаемое функцией ftok,
или константу IPC_PRIVATE, как обсуждалось в разделе 3.2.Аргумент size указывает размер сегмента в байтах. При создании нового сегмента разделяемой памяти нужно указать ненулевой размер. Если производится обращение к существующему сегменту, аргумент size должен быть нулевым.
Флаг oflag представляет собой комбинацию флагов доступа на чтение и запись из табл. 3.3. К ним могут быть добавлены с помощью логического сложения флаги IPC_CREAT или IPC_CREAT | IPC_EXCL, как уже говорилось в связи с рис. 3.2.
Новый сегмент инициализируется нулями.
Обратите внимание, что функция shmget создает или открывает сегмент разделяемой памяти, но не дает вызвавшему процессу доступа к нему. Для подключения сегмента памяти предназначена функция shmat, описанная в следующем разделе.
14.3. Функция shmat
После создания или открытия сегмента разделяемой памяти вызовом shmget его нужно подключить к адресному пространству процесса вызовом shmat:
Аргумент shmid — это идентификатор разделяемой памяти, возвращенный shmget. Функция shmat возвращает адрес начала области разделяемой памяти в адресном пространстве вызвавшего процесса. Правила, по которым формируется этот адрес, таковы:
■ если аргумент shmaddr представляет собой нулевой указатель, система сама выбирает начальный адрес для вызвавшего процесса. Это рекомендуемый (и обеспечивающий наилучшую совместимость) метод;
■ если shmaddr отличен от нуля, возвращаемый адрес зависит от того, был ли указан флаг SHM_RND (в аргументе flag ):
□ если флаг SHM_RND не указан, разделяемая память подключается непосредственно с адреса, указанного аргументом shmaddr,
□ если флаг SHM_RND указан, сегмент разделяемой памяти подключается с адреса, указанного аргументом shmaddr, округленного вниз до кратного константе SHMLBA. Аббревиатура LBA означает lower boundary address — нижний граничный адрес.
По умолчанию сегмент подключается для чтения и записи, если процесс обладает соответствующими разрешениями. В аргументе flag можно указать константу SHM_RDONLY, которая позволит установить доступ только на чтение.
14.4. Функция shmdt
После завершения работы с сегментом разделяемой памяти его следует отключить вызовом shmdt:
При завершении работы процесса все сегменты, которые не были отключены им явно, отключаются автоматически.
Обратите внимание, что эта функция не удаляет сегмент разделяемой памяти. Удаление осуществляется функцией shmctl с командой IPC_RMIO.