Н.В. Вдовикина, И.В. Машечкин, А.Н. Терехин, В.В. Тюляева - Программирование в ОС UNIX на языке Си (1114655), страница 15
Текст из файла (страница 15)
Вкачестве значения этого аргумента может быть указан флаг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. Тип данных union semun определен в файле<sys/sem.h> и выглядит следующим образом:union semun {int val; // значение одного семафораstruct semid_ds *buf;/* параметры массивасемафоров в целом */ushort*array;/* массив значенийсемафоров */}где struct semid_ds – структура, описанная в том же файле,в полях которой хранится информация обо всем наборе семафоров вцелом, а именно, количество семафоров в наборе, права доступа кнему и статистика доступа к массиву семафоров.Приведем некоторые наиболее часто используемые значенияаргумента cmd:IPC_STAT – скопировать управляющие параметры набора семафоров по адресу arg.buf;IPC_SET – заменить управляющие параметры набора семафоров на те, которые указаны в arg.buf. Чтобы выполнить эту операцию, процесс должен быть владельцем или создателем массива семафоров, либо обладать правами привилегированного пользователя,при этом процесс может изменить только владельца массива семафоров и права доступа к нему;IPC_RMID – удалить массив семафоров.
Чтобы выполнить этуоперацию, процесс должен быть владельцем или создателем массивасемафоров, либо обладать правами привилегированного пользователя;GETALL, SETALL – считать / установить значения всех семафоров в массив, на который указывает arg.array;GETVAL – возвратить значение семафора с номером num. Последний аргумент вызова игнорируется;SETVAL – установить значение семафора с номером num равным arg.val.94В случае успешного завершения вызов возвращает значение,соответствующее конкретной выполнявшейся операции (0, если неоговорено иное), в случае неудачи – -1.Отметим, что использование данного вызова с командамиGETVAL и GETALL позволяет процессу проверить значение семафорабез риска оказаться заблокированным.Команды же SETVAL и SETALL чаще всего используются дляинициализации семафоров, начальное значение которых по семантике алгоритма работы с ними должно быть отлично от нуля 17.Задача 1. Для бинарного семафора, единичное значение которого соответствует свободному ресурсу, а нулевое – занятому, с помощью системного вызова semop() реализовать операции P и V.struct sembufP={0,-1,0};struct sembufV={0,1,0};semop(semid,&P,1);/* Освобождение ресурса: */semop(semid,&V,1);Задача 2.