Н.В. Вдовикина, И.В. Машечкин, А.Н. Терехин, В.В. Тюляева - Программирование в ОС UNIX на языке Си (1114934), страница 14
Текст из файла (страница 14)
Если в результате вызова shmget() будетсоздана новая область разделяемой памяти, то ее размер будет соответствовать значению size. Если же процесс подключается к существующей области разделяемой памяти, то значение size должнобыть не более ее размера, иначе вызов вернет –1. Если процесс приподключении к существующей области разделяемой памяти указал варгументе size значение, меньшее ее фактического размера, то впо88следствии он сможет получить доступ только к первым size байтамэтой области.В заголовочном файле <sys/shm.h> определены константыSHMMIN и SHMMAX, задающий минимально возможный и максимальновозможный размер области разделяемой памяти.
Если процесс пытается создать область разделяемой памяти, размер которой не удовлетворяет этим границам, системный вызов shmget() окончится неудачей.Третий параметр определяет флаги, управляющие поведениемвызова. Подробнее алгоритм создания/подключения разделяемогоресурса был описан выше.В случае успешного завершения вызов возвращает положительное число – дескриптор области памяти, в случае неудачи - -1.Доступ к разделяемой памятиПри помощи вызова char *shmat(int shmid, char*shmaddr, int shmflg) процесс подсоединяет область разделяемой памяти, дескриптор которой указан в shmid, к своему виртуальному адресному пространству.
После выполнения этой операциипроцесс сможет читать и модифицировать данные, находящиеся вобласти разделяемой памяти, адресуя ее как любую другую областьв своем собственном виртуальном адресном пространстве.В качестве второго аргумента процесс может указать виртуальный адрес в своем адресном пространстве, начиная с которогонеобходимо подсоединить разделяемую память. Чаще всего, однако,в качестве значения этого аргумента передается 0, что означает, чтосистема сама может выбрать адрес начала разделяемой памяти.Примечание. Передача конкретного адреса в этом параметреимеет смысл в том случае, если, к примеру, в разделяемую памятьзаписываются указатели на нее же (например, в ней хранится связанный список) – в этой ситуации для того, чтобы использованиеэтих указателей имело смысл и было корректным для всех процессов, подключенных к памяти, важно, чтобы во всех процессах адресначала области разделяемой памяти совпадал.Третий аргумент представляет собой комбинацию флагов.
Вкачестве значения этого аргумента может быть указан флагSHM_RDONLY, который указывает на то, что подсоединяемая областьбудет использоваться только для чтения.Эта функция возвращает адрес, начиная с которого будет отображаться присоединяемая разделяемая память. В случае неудачивызов возвращает -1.Открепление разделяемой памяти89Вызов int shmdt(char *shmaddr) позволяет отсоединитьразделяемую память, ранее присоединенную посредством вызоваshmat().Параметр shmaddr − адрес прикрепленной к процессу памяти,который был получен при вызове shmat().В случае успешного выполнения функция возвращает 0, в случае неудачи -1.Управление разделяемой памятьюВызов int shmctl(int shmid, int cmd, struct shmid_ds*buf) используется для получения или изменения процессомуправляющих параметров, связанных с областью разделяемой памяти, наложения и снятия блокировки на нее и ее уничтожения.
Аргументы вызова — дескриптор области памяти, команда, которую необходимо выполнить, и структура, описывающая управляющие параметры области памяти. Тип shmid_ds описан в заголовочном файле <sys/shm.h>, и представляет собой структуру, в полях которойхранятся права доступа к области памяти, ее размер, число процессов, подсоединенных к ней в данный момент, и статистика обращений к области памяти.Возможные значения аргумента cmd:IPC_STAT – скопировать структуру, описывающую управляющие параметры области памяти по адресу, указанному в параметреbuf;IPC_SET – заменить структуру, описывающую управляющиепараметры области памяти, на структуру, находящуюся по адресу,указанному в параметре buf.
Выполнить эту операцию может процесс, у которого эффективный идентификатор пользователя совпадает с владельцем или создателем очереди, либо процесс с правамипривилегированного пользователя, при этом процесс может изменить только владельца области памяти и права доступа к ней;IPC_RMID – удалить разделяемую память. Как уже говорилось,удалить ресурс IPC может только процесс, у которого эффективныйидентификатор пользователя совпадает с владельцем или создателемресурса, либо процесс с правами привилегированного пользователя;SHM_LOCK, SHM_UNLOCK – блокировать или разблокировать область памяти. Выполнить эту операцию может только процесс с правами привилегированного пользователя.СемафорыСемафоры, как правило, используются для синхронизациидоступа нескольких процессов к другим разделяемым ресурсам, так90как сами по себе прочие средства IPC не предоставляют механизмасинхронизации.Классический семафор представляет собой особый вид числовой переменной, над которой определены две неделимые операции:уменьшение ее значения с возможным блокированием процесса иувеличение значения с возможным разблокированием одного из ранее заблокированных процессов.Как правило, использование классических семафоров в качестве средства синхронизации доступа к другим разделяемым объектам предполагает следующую схему:- с каждым разделяемым ресурсом связывается один семафориз набора;- положительное значение семафора означает возможностьдоступа к ресурсу (ресурс свободен), неположительное –отказ в доступе (ресурс занят);- перед тем как обратиться к ресурсу, процесс уменьшаетзначение соответствующего ему семафора, при этом, еслизначение семафора после уменьшения должно оказатьсяотрицательным, то процесс будет заблокирован до тех пор,пока семафор не примет такое значение, чтобы при уменьшении его значение оставалось неотрицательным;- закончив работу с ресурсом, процесс увеличивает значениесемафора (при этом разблокируется один из ранее заблокированных процессов, ожидающих увеличения значения семафора, если таковые имеются);- в случае реализации взаимного исключения используетсядвоичный семафор, т.е.
такой, что он может приниматьтолько значения 0 и 1: такой семафор всегда разрешаетдоступ к ресурсу не более чем одному процессу одновременно.Объект System V IPC представляет собой набор семафоров,причем каждый отдельный семафор в наборе является расширениемклассического понятия: если классический семафор предполагаетлишь одну, рассмотренную выше, схему использования его в качестве средства синхронизации конкурирующих процессов, то для семафора System V добавляется возможность блокирования на семафоре в ожидании его обнуления.Доступ к семафорам91Для получения доступа к массиву семафоров (или его создания) используется системный вызов int semget (key_t key, intnsems, int semflag).Первый параметр функции semget() – ключ для доступа кразделяемому ресурсу, второй – количество семафоров в создаваемом наборе (длина массива семафоров) и третий параметр – флаги,управляющие поведением вызова.
Подробнее процесс создания разделяемого ресурса описан выше. Отметим семантику прав доступа ксемафорам: процесс, имеющий право доступа к массиву семафоровпо чтению, может проверять значение семафоров; процесс, имеющий право доступа по записи, может как проверять, так и изменятьзначения семафоров.В случае, если среди флагов указан IPC_CREAT, аргументnsems должен представлять собой положительное число, если жеэтот флаг не указан, значение nsems игнорируется.
Отметим, что взаголовочном файле <sys/sem.h> определена константа SEMMSL, задающая максимально возможное число семафоров в наборе. Еслизначение аргумента nsems больше этого значения, вызов semget()завершится неудачно.В случае успеха вызов semget() возвращает положительныйдескриптор созданного разделяемого ресурса, в случае неудачи -1.Операции над семафорамиИспользуя полученный дескриптор, можно производить изменять значения одного или нескольких семафоров в наборе, а такжепроверять их значения на равенство нулю, для чего используетсясистемный вызов int semop (int semid, struct sembuf*semop, size_t nops).Этому вызову передаются следующие аргументы:semid – дескриптор массива семафоров;semop – массив из объектов типа struct sembuf, каждый изкоторых задает одну операцию над семафором;nops – длина массива semop.
Количество семафоров, над которыми процесс может одновременно производить операцию в одномвызове semop(), ограничено константой SEMOPM, описанной в файле<sys/sem.h>. Если процесс попытается вызвать semop() с параметром nops, большим этого значения, этот вызов вернет неуспех.Структура имеет sembuf вид:struct sembuf {short sem_num;short sem_op;short sem_flg;}/* номер семафора в векторе *//* производимая операция *//* флаги операции */92Общий принцип обработки этой структуры следующий:Пусть значение семафора с номером sem_num равноsem_val.1. если значение операции не равно нулю: оценивается значение суммы sem_val + sem_op. если эта сумма больше либо равна нулю, то значение данного семафора устанавливается равнымэтой сумме: sem_val = sem_val + sem_op если же эта сумма меньше нуля, то действие процесса будет приостановлено до тех пор, пока значение суммы sem_val + sem_op не станет больше либо равно нулю, после чего значение семафора устанавливается равным этой сумме: sem_val= sem_val + sem_op2.
Если код операции sem_op равен нулю: Если при этом значение семафора (sem_val) равнонулю, происходит немедленный возврат из вызова Иначе происходит блокирование процесса до техпор, пока значение семафора не обнулится, послечего происходит возврат из вызоваТаким образом, ненулевое значение поля sem_op обозначаетнеобходимость прибавить к текущему значению семафора значениеsem_op, а нулевое – дождаться обнуления семафора.Поле sem_flg в структуре sembuf содержит комбинацию флагов, влияющих на выполнение операции с семафором. В этом полеможет быть установлен флаг IPC_NOWAIT, который предписываетсоответствующей операции над семафором не блокировать процесс,а сразу возвращать управление из вызова semop().
Вызов semop() втакой ситуации вернет –1. Кроме того, в этом поле может быть установлен флаг SEM_UNDO, в этом случае система запомнит изменение значения семафора, произведенные данным вызовом, и по завершении процесса автоматически ликвидирует это изменение. Этопредохраняет от ситуации, когда процесс уменьшил значение семафора, начав работать с ресурсом, а потом, не увеличив значение семафора обратно, по какой-либо причине завершился. В этом случаеостальные процессы, ждущие доступа к ресурсу, оказались бы заблокированы навечно.Управление массивом семафоров.93С помощью системного вызова int semctl (int semid, intnum, int cmd, union semun arg) можно запрашивать и изменятьуправляющие параметры разделяемого ресурса, а также удалять его.Первый параметр вызова – дескриптор массива семафоров.Параметр num представляет собой индекс семафора в массиве, параметр cmd задает операцию, которая должна быть выполнена надданным семафором. Последний аргумент имеет тип union semun ииспользуется для считывания или задания управляющих параметроводного семафора или всего массива, в зависимости от значения аргумента cmd.