2011. Машбук (1114722), страница 47
Текст из файла (страница 47)
100. Разделяемая память.Рассмотрим набор системных вызовов для работы с разделяемой памятью. Длясоздания/подключения к ресурсу разделяемой памяти IPC используется функция shmget().#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>int shmget (key_t key, int size, int shmflg);Аргументы данной функции: key — ключ для доступа к разделяемой памяти; sizeзадает размер области памяти, к которой процесс желает получить доступ.
Если врезультате вызова shmget() будет создана новая область разделяемой памяти, то ее размербудет соответствовать значению size. Если же процесс подключается к существующейобласти разделяемой памяти, то значение size должно быть не более ее размера, иначевызов вернет -1. Заметим, что если процесс при подключении к существующей области174разделяемой памяти указал в аргументе size значение, меньшее ее фактического размера,то впоследствии он сможет получить доступ только к первым size байтам этой области.Третий параметр определяет флаги, управляющие поведением вызова.
Подробнееалгоритм создания/подключения разделяемого ресурса был описан выше.В случае успешного завершения вызов возвращает положительное число —дескриптор области памяти, в случае неудачи возвращается -1. Но наличие у процессадескриптора разделяемой памяти не дает ему возможности работать с ресурсом,поскольку при работе с памятью процесс работает в терминах адресов. Поэтомунеобходима еще одна функция, которая присоединяет полученную разделяемую память кадресному пространству процесса, — это функция shmat().#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>char *shmat(int shmid, char *shmaddr, int shmflg);При помощи этого вызова процесс подсоединяет область разделяемой памяти,дескриптор которой указан в shmid, к своему виртуальному адресному пространству.После выполнения этой операции процесс сможет читать и модифицировать данные,находящиеся в области разделяемой памяти, адресуя ее как любую другую область всвоем собственном виртуальном адресном пространстве.В качестве второго аргумента процесс может указать виртуальный адрес в своемадресном пространстве, начиная с которого необходимо подсоединить разделяемуюпамять.
Если в качестве значения этого аргумента передается 0, то это означает, чтосистема сама может выбрать адрес начала разделяемой памяти. Передача конкретногоадреса (положительного целого) в этом параметре имеет смысл лишь в определенныхслучаях, и это означает, что процесс желает связать начало области разделяемой памяти сконкретным адресом. В подобных случаях необходимо учитывать, что возможныколлизии с имеющимся адресным пространством.Третий аргумент представляет собой комбинацию флагов.
В качестве значенияэтого аргумента может быть указан флаг SHM_RDONLY, который указывает на то, чтоподсоединяемая область будет использоваться только для чтения. Реализация тех илииных флагов будет зависеть от аппаратной поддержки соответствующего свойства. Еслиаппаратура не поддерживает защиту памяти от записи, то при установке флагаSHM_RDONLY ошибка, связанная с модификацией содержимого памяти, не сможет бытьобнаружена (поскольку программным способом невозможно выявить, в какой моментпроисходит обращение на запись в данную область памяти).Эта функция возвращает адрес (указатель) в виртуальном адресном пространствепроцесса, начиная с которого будет отображаться присоединяемая разделяемая память.
Ис этим указателем можно работать стандартными средствами языка C. В случае неудачивызов возвращает -1.Соответственно, для открепления разделяемой памяти от адресного пространствапроцесса используется функция shmdt().#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>int shmdt(char *shmaddr);Данный вызов позволяет отсоединить разделяемую память, ранее присоединеннуюпосредством вызова shmat(). Параметр shmaddr — адрес прикрепленной к процессу175памяти, который был получен при вызове shmat().
В случае успешного выполненияфункция вернет значение 0, в случае неудачи возвращается -1.И, напоследок, рассмотрим функцию shmctl() управления ресурсом разделяемаяпамять.#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>int shmctl(int shmid, int cmd, struct shmid_ds *buf);Данный вызов используется для получения или изменения процессомуправляющих параметров, связанных с областью разделяемой памяти, наложения иснятия блокировки на нее и ее уничтожения.
Аргументы вызова — дескриптор областипамяти, команда, которую необходимо выполнить, и структура, описывающаяуправляющие параметры области памяти. Тип shmid_ds описан в заголовочном файле<sys/shm.h>, и представляет собой структуру, в полях которой хранятся права доступак области памяти, ее размер, число процессов, подсоединенных к ней в данный момент, истатистика обращений к области памяти.Возможные значения аргумента cmd:IPC_STAT – скопировать структуру, описывающую управляющие параметрыобласти памяти по адресу, указанному в параметре bufIPC_SET – заменить структуру, описывающую управляющие параметры областипамяти, на структуру, находящуюся по адресу, указанному в параметре buf.
Выполнитьэту операцию может процесс, у которого эффективный идентификатор пользователясовпадает с владельцем или создателем очереди, либо процесс с правамипривилегированного пользователя, при этом процесс может изменить только владельцаобласти памяти и права доступа к ней.IPC_RMID – удалить очередь. Как уже говорилось, удалить очередь может толькопроцесс, у которого эффективный идентификатор пользователя совпадает с владельцемили создателем очереди, либо процесс с правами привилегированного пользователя.SHM_LOCK, SHM_UNLOCK – блокировать или разблокировать область памяти.Выполнить эту операцию может только процесс с правами привилегированногопользователя.Это единственные средства синхронизации в данном ресурсе, их реализациядолжна поддерживаться аппаратурой.Пример.
Схема работы с общей памятью в рамках одного процесса. В данномпримере процесс создает ресурс разделяемая память, размером в 100 байт (и ссоответствующими флагами), присоединяет ее к своему адресному пространству; приэтом указатель на начало данной области сохраняется в переменной shmaddr. Дальшепроцесс производит различные манипуляции, а перед своим завершением он удаляетданную область разделяемой памяти. В данном примере считается, что putm() иwaitprocess() – некие пользовательские функции, определенные в другом месте.int main(int argc, char **argv){key_t key;char *shmaddr;key = ftok(“/tmp/ter”, ’S’);shmid = shmget(key, 100, 0666 | IPC_CREAT | IPC_EXCL);shmaddr = shmat(shmid, NULL, 0);176/* работаем с разделяемой памятью, как с обычной */putm(shmaddr);waitprocess();shmctl(shmid, IPC_RMID, NULL);return 0;}3.2.3 Массив семафоров IPCСемафоры представляют собой одну из форм IPC и обычно используются длясинхронизации доступа нескольких процессов к разделяемым ресурсам, так как сами посебе другие средства IPC не предоставляют механизма синхронизации.Как уже говорилось, семафор представляет собой особый вид числовойпеременной, над которой определены две неделимые операции: уменьшение ее значения свозможным блокированием процесса и увеличение значения с возможнымразблокированием одного из ранее заблокированных процессов.
Объект System V IPCпредставляет собой набор семафоров. Как правило, использование семафоров в качествесредства синхронизации доступа к другим разделяемым объектам предполагаетследующую схему:- с каждым разделяемым ресурсом связывается один семафор из набора;- положительное значение семафора означает возможность доступа кресурсу (ресурс свободен), неположительное – отказ в доступе (ресурсзанят);- перед тем как обратиться к ресурсу, процесс уменьшает значениесоответствующего ему семафора, при этом, если значение семафорапосле уменьшения должно оказаться отрицательным, то процесс будетзаблокирован до тех пор, пока семафор не примет такое значение, чтобыпри уменьшении его значение оставалось неотрицательным;- закончив работу с ресурсом, процесс увеличивает значение семафора(при этом разблокируется один из ранее заблокированных процессов,ожидающих увеличения значения семафора, если таковые имеются);- в случае реализации взаимного исключения используется двоичныйсемафор, т.е.
такой, что он может принимать только значения 0 и 1:такой семафор всегда разрешает доступ к ресурсу не более чем одномупроцессу одновременноРассмотрим набор вызовов для оперирования с семафорами в UNIX System V.3.2.3.1 Доступ к семафоруДля получения доступа к массиву семафоров (или его создания) используетсясистемный вызов semget():#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>int semget (key_t key, int nsems, int semflag);Первый параметр функции semget() – ключ для доступа к разделяемому ресурсу,второй - количество семафоров в создаваемом наборе (длина массива семафоров) и третийпараметр – флаги, управляющие поведением вызова.