Чтение онлайн

ЖАНРЫ

Программирование для Linux. Профессиональный подход

Самьюэл Алекс

Шрифт:

В следующем фрагменте программы функция

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

int segment_id = shmget(shm_key, getpagesize,

 IPC_CREAT | S_IRUSR | S_IWUSR);

В случае успешного завершения функция возвращает идентификатор сегмента. Если сегмент уже существует, проверяются нрава доступа к нему.

5.1.4. Подключение и отключение сегментов

Чтобы сделать сегмент памяти общедоступным, процесс должен

подключить его с помощью функции
shmat
. В первом ее аргументе передается идентификатор сегмента, возвращенный функцией
shmget
. Второй аргумент — это указатель, определяющий, где в адресном пространстве процесса необходимо создать привязку на совместно используемую область памяти. Если задать значение
NULL
, ОС Linux выберет первый доступный адрес. Третий аргумент может содержать следующие флаги.

■ 

SHM_RND
. Указывает на то, что адрес, заданный во втором параметре, должен быть округлен, чтобы стать кратным размеру страницы. Если этот флаг не указан, необходимо самостоятельно позаботиться о выравнивании сегмента по границе страницы.

■ 

SHM_RDONLY
. Указывает на то. что сегмент доступен только для чтения, но не для записи.

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

fork
, унаследует этот адрес и в случае необходимости сможет отключить сегмент.

По завершении работы с сегментом его необходимо отключить с помощью функции

shmdt
. Ей следует передать адрес, возвращаемый функцией
shmat
. Если текущий процесс был последним, кто ссылался на сегмент, сегмент удаляется из памяти. Функции
exit
и
exec
автоматически отключают сегменты.

5.1.5. Контроль и освобождение совместно используемой памяти

Функция

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

Чтобы получить информацию о сегменте, укажите в качестве второго параметра константу

IPC_STAT
, а в третьем параметре передайте указатель на структуру
shmid_ds
.

Чтобы удалить сегмент, передайте во втором параметре константу

IPC_RMID
, а в третьем параметре —
NULL
. Сегмент удаляется, когда последний подключивший его процесс отключает сегмент.

Каждый совместно используемый сегмент должен явно освобождаться с помощью функции

shmctl
, чтобы случайно не был превышен системный лимит на общее число таких сегментов. Функции
exit
и
exec
отключают сегменты, но не освобождают их.

Описание других операций, выполняемых над совместно используемыми сегментами памяти, можно найти на

man
– странице функции
shmctl
.

5.1.6. Пример программы

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

Листинг 5.1. (shm.c) Пример совместного использования памяти

#include <stdio.h>

#include <sys/shm.h>

#include <sys/stat.h>

int main {

 int segment_id;

 char* shared_memory;

 struct shmid_ds shmbuffer;

 int segment_size;

 const int shared_segment_size = 0x6400;

 /*
Выделение совместно используемого сегмента. */

 segment_id =

shmget(IPC_PRIVATE, shared_segment_size,

IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR);

 /* Подключение сегмента. */

 shared_memory = (char*)shmat(segment_id, 0, 0);

 printf("shared memory attached at address %p\n",

shared_memory);

 /* Определение размера сегмента. */

 shmctl(segment_id, IPC_STAT, &shmbuffer);

 segment_size = shmbuffer.shm_segsz;

 printf("segment size: %d\n", segment_size);

 /* Запись строки в сегмент. */

 sprintf(shared_memory, "Hello, world.");

 /* Отключение сегмента. */

 shmdt(shared_memory);

 /* Повторное подключение сегмента, но по другому адресу! */

 shared_memory =

(char*)shmat(segment_id, (void*) 0x5000000, 0);

 printf("shared memory reattached at address %p\n",

shared_memory);

 /* Отображение строки, хранящейся в совместно используемой

памяти. */

 printf("%s\n", shared_memory);

 /* Отключение сегмента. */

 shmdt(shared_memory);

 /* Освобождение сегмента. */

 shmctl(segment_id, IPC_RMID, 0);

 return 0;

}

5.1.7. Отладка

Команда

ipcs
выдает информацию о взаимодействии процессов, включая сведения о совместно используемых сегментах (для этого следует задать флаг
– m
). Например, в показанном ниже случае сообщается о том, что используется один такой сегмент, с номером 1627649:

% ipcs -m

– ------- Shared Memory Segments --------

key shmid owner perms bytes nattch status

0x00000000 1627649 user 640 25600 0

Если этот сегмент был по ошибке "забыт" какой-то программой, его можно удалить с помощью команды

ipcrm
:

% ipcrm shm 1627649

5.1.8. Проблема выбора

Благодаря совместному использованию памяти можно организовать быстрое двустороннее взаимодействие произвольного числа процессов. Любой пользователь сможет получать доступ к сегментам памяти для чтения/записи, но для этого программа должна следовать определенным правилам, позволяющим избегать конкуренции (чтобы, например, информация не оказалась перезаписанной до того, как будет прочитана). К сожалению, Linux не гарантирует монопольный доступ к сегменту, даже если он был создан с указанием флага

IPC_PRIVATE
.

Поделиться с друзьями: