DAY14 (1114704), страница 2
Текст из файла (страница 2)
Общая схема работы с разделяемыми ресурсами такова - есть некоторый процесс-автор, создающий ресурс с какими-либо параметрами. При создании ресурса разделяемой памяти задаются три параметра - ключ, права доступа и размер области памяти. После создания ресурса к нему могут быть подключены процессы, желающие работать с этой памятью. Соответственно, имеется действие подключения к ресурсу с помощью ключа, который генерируется по тем же правилам, что и ключ для создания ресурса. Понятно, что здесь имеется момент некоторой рассинхронизации, который связан с тем, что потребитель разделяемого ресурса (процесс, который будет работать с ресурсом, но не является его автором) может быть запущен и начать подключаться до запуска автора ресурса. В этой ситуации особого криминала нету, так как имеются функции управления доступом к разделяемому ресурсу, с использованием которых можно установить некоторые опции, определяющие правила работы функций, взаимодействующих с разделяемыми ресурсами. В частности, существует опция, заставляющая процесс дождаться появления ресурса. Это также, может быть, не очень хорошо, например, автор может так и не появиться, но другого выхода нет, это есть некоторые накладные расходы. Вот в общих словах - что есть что.
Первая функция - создание общей памяти.
int shmget (key_t key, int size, int shmemflg);
key - ключ разделяемой памяти;
size - размер раздела памяти, который должен быть создан;
shmemflg - флаги;
Данная функция возвращает идентификатор ресурса, который ассоциируется с созданным по данному запросу разделяемым ресурсом. То есть в рамках процесса по аналогии с файловыми дескрипторами каждому разделяемому ресурсу определяется его идентификатор. Надо разделять ключ - это общесистемный атрибут, и идентификатор, используя который мы работаем с конкретным разделяемым ресурсом в рамках процесса.
С помощью этой функции можно как создать новый разделяемый ресурс “память”, так и подключиться к существующему разделяемому ресурсу. В частности, если в качестве параметра-флага берется IPC_CREAT, то если к данному моменту нет разделяемого ресурса с указанным ключом, то он будет создан, если таковой существует, то произойдет подключение процесса к данному разделяемому ресурсу. Есть альтернатива этого флага - флаг IPC_EXECL, он позволяет проверить и подключиться к существующему ресурсу - если ресурс существует, то функция подключает к нему процесс и возвращает код идентификатора, если же ресурс не существует, то функция возвращает -1 и соответствующий код в errno.
Следующая функция - доступ к разделяемой памяти:
char *shmat(int shmid, char *shmaddr, int shmflg);
shmid - идентификатор разделяемого ресурса;
shmaddr - адрес, с которого мы хотели бы разместить разделяемую память;
При этом, если значение shmaddr - адрес, то память будет подключена, начиная с этого адреса, если его значение - нуль, то система сама подберет адрес начала. Также в качестве значений этого аргумента могут быть некоторые предопределенные константы, которые позволяют организовать, в частности выравнивание адреса по странице или началу сегмента памяти.
shmflg - флаги. Они определяют разные режимы доступа, в частности, есть флаг SHM_RDONLY.
Эта функция возвращает указатель на адрес, начиная с которого будет начинаться запрашиваемая разделяемая память. Если происходит ошибка, то возвращается -1.
Хотелось бы немного поговорить о правах доступа. Они реально могут использоваться и корректно работать не всегда. Так как, если аппаратно не поддерживается закрытие области данных на чтение или на запись, то в этом случае могут возникнуть проблемы с реализацией такого рода флагов. Во-первых, они не будут работать, так как мы получаем указатель и начинаем работать с указателем, как с указателем, и общая схема здесь не предусматривает защиты. Второе, можно программно сделать так, чтобы работали флаги, но тогда мы не сможем указывать произвольный адрес, в этом случае система будет подставлять и возвращать в качестве адреса разделенной памяти некоторые свои адреса, обращение к которым будет создавать заведомо ошибочную ситуацию, возникнет прерывание процесса, во время которого система посмотрит - кто и почему был инициатором некорректного обращения к памяти, и если тот процесс имеет нужные права доступа – система подставит нужные адреса, иначе доступ для процесса будет заблокирован. Это похоже на установку контрольной точки в программе при отладке, когда создавалась заведомо ошибочная ситуация для того, чтобы можно было прервать процесс и оценить его состояние.
Третья функция - открепление разделяемой памяти:
int shmdt(char *shmaddr);
shmaddr - адрес прикрепленной к процессу памяти, который был получен при подключении памяти в начале работы.
Четвертая функция - управление разделяемой памятью:
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
shmid - идентификатор разделяемой памяти
cmd - команда управления.
В частности, могут быть команды: IPC_SET (сменить права доступа и владельца ресурса - для этого надо иметь идентификатор автора данного ресурса или суперпользователя), IPC_STAT (запросить состояние ресурса - в этом случае заполняется информация в структуру, указатель на которую передается третьим параметром), IPC_RMID (уничтожение ресурса - после того, как автор создал процесс - с ним работают процессы, которые подключаются и отключаются, но не уничтожают ресурс, а с помощью данной команды мы уничтожаем ресурс в системе).
Это все, что касается функций управления разделяемой памятью.