Размер совместно используемого сегмента кратен размеру страницы ВП. В Linux последняя величина обычно равна 4 Кбайт, но никогда не помешает это проверить с помощью функции getpagesize()
.
5.1.3. Выделение сегментов памяти
Процесс выделяет сегмент памяти с помощью функции shmget()
. Первым аргументом функции является целочисленный ключ, идентифицирующий создаваемый сегмент. Если несвязанные процессы хотят получить доступ к одному и тому же сегменту, они должны указать одинаковый ключ. К сожалению, ничто не мешает посторонним процессам выбрать тот же самый ключ сегмента, а это приведет к системному конфликту. Указание специальной константы IPC_PRIVATE
в качестве ключа позволяет гарантировать, что будет создан совершенно новый сегмент.
Во втором аргументе функции задается размер сегмента в байтах. Это значение округляется, чтобы быть кратным размеру страницы ВП.
Третий параметр содержит набор битовых флагов. Перечислим наиболее важные из них.
■ IPC_CREAT
. Указывает на то, что создается новый сегмент, которому присваивается заданный ключ.
■ IPC_EXCL
. Всегда используется совместно с флагом IPC_CREAT
и заставляет функцию shmget()
выдать ошибку в случае, когда сегмент с указанным ключом уже существует. Если флаг не указан и возникает описанная ситуация, функция shmget()
возвращает идентификатор существующего сегмента, не создавая новый сегмент.
■ Флаги режима . В эту группу входят 9 флагов, задающих права доступа к сегменту для владельца, группы и остальных пользователей. Биты выполнения игнорируются. Проще всего задавать права доступа с помощью констант, определенных в файле (они описаны на man
-странице функции stat()
). [15] Эти же константы используются при работе с файлами. Они описываются в разделе 10.3. "Права доступа к файлам".
Например, флаги S_IRUSR
и S_IWUSR
предоставляют право чтения и записи владельцу сегмента, а флаги S_IROTH
и S_IWOTH
предоставляют аналогичные права остальным пользователям.
В следующем фрагменте программы функция 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
. Сегмент удаляется, когда последний подключивший его процесс отключает сегмент.
Читать дальше