Разделяемая память Posix реализуется с помощью функции mmap, обсуждавшейся в предыдущей главе. Сначала вызывается функция shm_open с именем объекта Posix IPC в качестве одного из аргументов. Эта функция возвращает дескриптор, который затем передается функции mmap. Результат аналогичен отображению файла в память, но разделяемая память Posix не обязательно реализуется через файл.

Поскольку доступ к объектам разделяемой памяти может быть получен через дескриптор, для установки размера объекта используется функция ftruncate, а информация о существующем объекте (биты разрешений, идентификаторы пользователя и группы, размер) возвращается функцией fstat.

В главах, рассказывающих об очередях сообщений и семафорах Posix, мы приводили примеры их реализации через отображение в память (разделы 5.8 и 10.15). Для разделяемой памяти Posix мы этого делать не будем, поскольку реализация тривиальна. Если мы готовы использовать отображение в файл (что и сделано в Solaris и Digital Unix), shm_open реализуется через open, a shm_unlink — через unlink.

<p>Упражнения</p>

1. Измените программы из листингов 12.6 и 12.7 таким образом, чтобы они работали с разделяемой памятью Posix, а не с отображаемым в память файлом. Убедитесь, что результаты будут такими же, как и для отображаемого в память файла.

2. В циклах for в листингах 13.3 и 13.4 используется команда *ptr++ для перебора элементов массива. Не лучше ли было бы использовать ptr[i]? 

<p>ГЛАВА 14</p><p>Разделяемая память System V</p><p>14.1. Введение</p>

Основные принципы разделяемой памяти System V совпадают с концепцией разделяемой памяти Posix. Вместо вызовов shm_open и mmap в этой системе используются вызовы shmget и shmat.

Для каждого сегмента разделяемой памяти ядро хранит нижеследующую структуру, определенную в заголовочном файле sys/shm.h:

struct shmid_ds {

 struct ipc_perm shm_perm; /* структура разрешений */

 size_t shm_segsz; /* размер сегмента */

 pid_t shm_lpid; /* идентификатор процесса, выполнившего последнюю операцию */

 pid_t shm_cpid; /* идентификатор процесса-создателя */

 shmatt_t shm_nattch; /* текущее количество подключений */

 shmat_t shm_cnattch; /* количество подключений in-core */

 time_t shm_atime; /* время последнего подключения */

 time_t shm_dtime; /* время последнего отключения */

 time_t shm_ctime; /* время последнего изменения данной структуры */

};

Структура ipc_perm была описана в разделе 3.3; она содержит разрешения доступа к сегменту разделяемой памяти.

<p>14.2. Функция shmget</p>

С помощью функции shmget можно создать новый сегмент разделяемой памяти или подключиться к существующему:

#include sys/shm.h

int shmget(key_t key, size_t size, int oflag);

/* Возвращает идентификатор разделяемой памяти в случае успешного завершения. –1 –в случае ошибки */

Возвращаемое целочисленное значение называется идентификатором разделяемой памяти. Он используется с тремя другими функциями shmXXX.

Аргумент key может содержать значение, возвращаемое функцией ftok, или константу IPC_PRIVATE, как обсуждалось в разделе 3.2.

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

Флаг oflag представляет собой комбинацию флагов доступа на чтение и запись из табл. 3.3. К ним могут быть добавлены с помощью логического сложения флаги IPC_CREAT или IPC_CREAT | IPC_EXCL, как уже говорилось в связи с рис. 3.2.

Новый сегмент инициализируется нулями.

Обратите внимание, что функция shmget создает или открывает сегмент разделяемой памяти, но не дает вызвавшему процессу доступа к нему. Для подключения сегмента памяти предназначена функция shmat, описанная в следующем разделе.

<p>14.3. Функция shmat</p>

После создания или открытия сегмента разделяемой памяти вызовом shmget его нужно подключить к адресному пространству процесса вызовом shmat:

#include sys/shm.h

void *shmat(int shmid, const void *shmaddr, int flag);

/* Возвращает начальный адрес полученной области в случае успешного завершения. –1 –в случае ошибки */

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже