shmget - присваивает идентификатор разделяемому сегменту памяти
СИНТАКСИС
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, int size, int shmflg);
ОПИСАНИЕ
shmget() возвращает идентификатор разделяемому сегменту памяти, соответствующий значению аргумента key. Создается новый разделяемый сегмент памяти с размером, округленным в большую сторону от величины size( кратный PAGE_SIZE), если значение key равно IPC_PRIVATE или если значение key не равно IPC_PRIVATE и нет идентификатора, соответствующего key; причем, выражение shmflg&IPC_CREAT истинно. Поле
shmflg состоит из:
IPC_CREAT - служит для создания нового сегмента. Если этого флага нет, то функция shmget() будет искать сегмент, соответствующий ключу key; затем она проверит, имеет ли пользователь права на получение shmid, соответствующего этому сегменту, и удостоверится, не помечен ли сегмент на удаление.
IPC_EXCL - используется совместно с IPC_CREAT для того, чтобы не создавать существующий сегмент заново.
mode_flags (младшие 9 битов) - указывают на права хозяина, группы и др. В данный момент права системой не используются.
Если создается новый сегмент, то права доступа копируются из shmflg в shm_perm, являющийся членом структуры shmid_ds, которая определяет сегмент. Структура shmid_ds выглядит так:
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; /* идентификатор процесса создателя*/
unsigned short shm_lpid; /* идентификатор последнего пользователя*/
short shm_nattch; /* количество присоединений */
};
Так же, во время создания сегмента, системный вызов инициализирует структуру сегмента разделяемой памяти shmid_ds следующим образом: устанавливаемые значения
shm_perm.cuid и shm_perm.uid становятся равными значению идентификатора эффективного пользователя вызывающего процесса.
shm_perm.cgid и shm_perm.gid устанавливаются равными идентификатору эффективной группы пользователей вызывающего процесса.
Младшим 9-и битам shm_perm.mode присваивается значение младших 9-и битов shmflg.
shm_segsz присваивается значение size. Устанавливаемое значение shm_lpid, shm_nattch, shm_atime и shm_dtime становится равным нулю.
shm_ctime устанавливается на текущее время.
Если сегмент уже существет, то права доступа подтверждаются, а проверка производится для того, чтобы убедиться, что сегмент не помечен на удаление.
СИСТЕМНЫЕ ВЫЗОВЫ
fork() - После выполнения команды fork() дочерний процесс наследует подключаемые к нему разделяемые сегменты памяти.
exec() - После выполнения команды exec() все подключаемые к процессу разделяемые сегменты памяти отключаются от него, но не удаляются.
exit() - По завершении exit() все подключенные разделяемые сегменты памяти отключаются (но не удаляются).
ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При удачном завершении вызова возвращается идентификатор сегмента shmid, и -1 при ошибке.
SHMCTL
shmctl - производит операции по управлению разделяемыми сегментами памяти
СИНТАКСИС
#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
ОПИСАНИЕ
shmctl() позволяет пользователю получать информацию о разделяемых сегментах памяти, устанавливать владельца, группу разделяемого сегмента, права на него; эта функция может также удалить сегмент. Информация о сегменте, которая находится в shmid, возвращается в структуру shmid_ds :
Значения аргумента cmds могут быть следующими:
IPC_STAT - используется для копирования информации о сегменте в буфер buf. Пользователь должен иметь права на чтение сегмента read.
IPC_SET - используется для применения пользовательских изменений к содержимому полей uid, gid или mode в структуре shm_perms. Используются только младшие 9 битов mode. Поле shm_ctime тоже обновляется. Пользователь должен быть владельцем, создателем или суперпользователем процесса.
IPC_RMID - используется для пометки сегмента как удаленного. Сегмент будет удален после отключения (например, когда поле shm_nattch ассоциированной структуры shmid_ds равно нулю). Пользователь должен быть владельцем, создателем или суперпользователем процесса.
Пользователь должен удостовериться, что сегмент удален; иначе страницы, которые не были удалены, останутся в памяти или в разделе подкачки.
Вдобавок, суперпользователь может запретить или разрешить подкачку разделяемого сегмента памяти при помощи следующих команд cmds (это применимо только для Linux):
SHM_LOCK - запретить подкачку разделяемого сегмента памяти. После блокировки страницы должны находиться в памяти.
SHM_UNLOCK - разрешить подкачку сегмента.
Вызовы IPC_INFO, SHM_STAT и SHM_INFO используются программой ipcs() для получения информации о выделенных ресурсах. В будущем они могут быть по необходимости изменены или вынесены в файловую систему proc.
СИСТЕМНЫЕ ВЫЗОВЫ
fork() - После команды fork() дочерние процессы наследуют сегменты разделяемой памяти.
exec() - После команды exec () все подключенные сегменты разделяемой памяти отключаются (но не удаляются).
exit() - Если выполнена команда exit(), все сегменты разделяемой памяти отключаются (но не удаляются).
ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При удачном выполнении возвращается 0, а при ошибке -1.
SHMOP
shmop - работает с разделяемой памятью
СИНТАКСИС
#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
int shmdt(const void *shmaddr);
ОПИСАНИЕ
Функция shmat подстыковывает сегмент разделяемой памяти shmid к адресному пространству вызывающего процесса. Адрес подстыковываемого сегмента определяется shmaddr с помощью одного из перечисленных ниже критериев:
· Если shmaddr равен NULL, то система выбирает для подстыкованного сегмента подходящий (неиспользованный) адрес.
· Если shmaddr не равен NULL, а в поле shmflg включен флаг SHM_RND, то подстыковка производится по адресу shmaddr, округленному вниз до ближайшего кратного SHMLBA. В противном случае shmaddr должен быть округленным до размера страницы адресом, к которому производится подстыковка.
· Если в поле shmflg включен флаг SHM_RDONLY, то подстыковываемый сегмент будет доступен только для чтения, и вызывающий процесс должен иметь права на чтение этого сегмента. Иначе, сегмент будет доступен для чтения и записи, и у процесса должны быть соответствующие права. Сегментов "только-запись" не существует.
Значение brk вызывающего процесса подстыковкой не изменяется. При завершении работы процесса сегмент будет отстыкован. Один и тот же сегмент может быть подстыкован в адресное пространство процесса несколько раз, как "только для чтения", так и в режиме "чтение-запись".
При удачном выполнении системный вызов shmat обновляет содержимое структуры shmid_ds, связанной с разделяемым сегментом памяти, следующим образом:
shm_atime устанавливается в текущее время.
shm_lpid устанавливается в идентификатор вызывающего процесса.
shm_nattch увеличивается на 1.
Заметьте, что пристыковка производится и в том случае, если пристыковываемый сегмент помечен на удаление.
Функция shmdt отстыковывает сегмент разделяемой памяти, находящийся по адресу shmaddr, от адресного пространства вызвающего процесса. Отстыковываемый сегмент должен быть среди пристыкованных ранее функцией shmat. Параметр shmaddr должен быть равен значению, которое возвратила соответствующая функция shmat.
При удачном выполнении системный вызов shmdt обновляет содержимое структуры shmid_ds, связанной с разделяемым сегментом памяти, следующим образом:
shm_dtime устанавливается в текущее время.
shm_lpid устанавливается в идентификатор вызывающего процесса.
shm_nattch уменьшается на 1. Если это значение становится равным 0, а сегмент помечен на удаление, то сугмент удаляется из памяти. Эта функция освобождает занятую ранее этим сегментом область памяти в адресном пространстве процесса.
СИСТЕМНЫЕ ВЫЗОВЫ
fork() - При исполнении fork() дочернии процесс наследует пристыкованные сегменты разделяемой памяти.
exec() - При исполнении exec() все подстыкованные сегменты памяти отстыковываются от процесса.
exit () - При исполнении exit() все подстыкованные сегменты памяти отстыковываются от процесса.
ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При ошибке обе функции возвращают -1, а переменной errno присваивается номер ошибки. При удачном выполнении shmat возвращает адрес подстыкованного сегмента памяти, а shmdt возвращает 0.
Пример программы
Программа client читает данные (числа) из файла и записывает их в область разделяемой памяти. Программа server читает данные из разделяемой памяти, суммирует их и записывает результат в файл. Внимание! Для получения ключа необходимо создать файл с именем “sem” в каталоге программы.
Текст программы
Файл server.c
#include"shmem.h" //описание структуры семафоров и памяти
FILE *fd; //дескриптор файла результатов
int i; //счетчик
float sum=0; //сумма чисел
mem_sh *memptr; //указатель на структуру разделяемой памяти
key_t key; //ключ доступа к семафору
int shmid; //дескриптор разделяемой памяти
int semid; //дескриптор семафора
int main(void)
{
printf("\n\t\t.:SERVER:.\n");
key=ftok("sem",'A'); //получаем ключ для сервера
shmid=shmget(key,100,IPC_CREAT|PERM); //получаем деск. разделяемой памяти
memptr=(mem_sh*) shmat (shmid,0,0);//присоединяем память к памяти сервера