Читаем Linux: Полное руководство полностью

 semctl(sid, 0, IPC_SET, opts);

}

<p>26.7. Разделяемые сегменты памяти</p>

Сегменты памяти разделяются между несколькими процессами. Один процесс создает сегмент памяти, а другие в любом количестве — используют. Разделяемые сегменты памяти — это самый быстрый способ IPC.

Для каждого разделяемого сегмента памяти ядро поддерживает специальную структуру — shmid_ds, описанную в файле /usr/src/linux/include/linux/shm.h:

struct shmid_ds {

 struct ipc_perm shm_perm; /* права доступа */

 int shm_segsz; /* размеры сегмента в байтах */

 time_t shm_atime; /* время последней привязки */

 time_t shm_dtime; /* время последней отвязки */

 time_t shm_ctime; /* время последнего изменения */

 unsigned short shm_cpid; /* PID создателя */

 /* PID последнего процесса-пользователя сегмента */

 unsigned short shm_lpid;

 short shm_nattch; /* число привязок */

 unsigned short shm_npages;

 /* размеры сегмента (в страницах) */

 /* массив указателей на $frames -> S$*/

 unsigned long *shm_pages;

 struct vm_area_struct *attaches;

 /* дескрипторы для привязок */

};

Я немного сократил эту структуру, оставив описание только нужных нам полей. Полагаю, что вы в нем разберетесь. Возможно, вас заинтересовали термины «привязка» и «отвязка». Привязка — это размещение сегмента в адресном пространстве процесса, подключение к разделяемому сегменту памяти (РСП). Отвязка, соответственно, — отключение, Поле shm_nattch содержит количество привязок к РСП на данный момент.

Для создания нового РСП используется системный вызов shmget(). Этот же вызов используется для подключения к уже существующему РСП.

int shmget(key_t key, int size, int shmflg);

Первый аргумент — это ключ IPC, полученный с помощью ftok(), второй — размер РСП в байтах, а третий — флаги системного вызова shmget. Если установлен флаг IPC_CREAT, системный вызов создаст новый РСП или подключится к уже существующему сегменту, если обнаружится, что уже есть такой сегмент (с таким же значением ключа). Если установлен флаг IPC_EXCL вместе с IPC_CREAT (сам по себе он бесполезен) подключение к существующему РСП запрещается.

Системный вызов shmget() возвращает идентификатор РСП или -1, если произошла ошибка. Переменная errno устанавливается так:

♦ EACCESS — не хватает полномочий для доступа к сегменту;

♦ EINVAL — неправильно заданы размеры сегмента;

♦ EEXISTS — сегмент уже существует, создание невозможно. Вы получите эту ошибку, если будете использовать флаг IPC_EXCL вместе с IPC_CREAT при условии, что сегмент уже существует;

♦ IDRM — сегмент помечен на удаление или уже удален;

♦ ENOMEM — не хватает памяти для создания сегмента.

Приведем пример функции открытия/создания РСП:

int open_shms(key_t key, int size) {

 return (shmget(key, size, IPC_CREAT | 0660 )) == -1));

}

После получения идентификатора РСП мы должны «привязаться» к этому сегменту, то есть разместить сегмент в своем адресном пространстве. Для этого используется системный вызов shmat() (shared memory attachment):

int shmat(int shmid, char *shmaddr, int shmflg);

Первый аргумент — это идентификатор РСП, который мы получаем с помощью предыдущего вызова. Второй аргумент — это адрес привязки. Если указать вместо адреса ноль, то ядро само найдет нераспределенную область.

Третий аргумент — это флаги. Обычно используется два флага:

♦ SHM_RND — переданный адрес будет округлен до ближайшей страницы (если вы сами указываете адрес);

♦ SHM_RDONLY — РСП будет доступен только для чтения.

В случае успеха shmat() возвращает адрес, по которому сегмент был привязан к процессу, или -1, если произошла ошибка. Переменная errno может принимать всего три значения:

♦ EACCESS — нет доступа;

♦ ENOMEM — не хватает памяти;

♦ EINVAL — ошибка в параметрах, то есть неправильное значение ID или адреса привязки (shmaddr).

Пример привязки:

char *ptr;

prt = shmat(sh_id,0,0);

После привязки сегмента к адресному пространству доступны операции чтения и записи, которые очень напоминают работу с простыми указателями.

Для снятия привязки используется системный вызов shmdt():

int shmdt(char *shmaddr);

Перейти на страницу:

Все книги серии Полное руководство

Похожие книги

Все жанры