Н.В. Вдовикина, А.В. Казунин, И.В. Машечкин, А.Н. Техехин - Системное программное обеспечение - взаимодействие процессов (1114927), страница 19
Текст из файла (страница 19)
В случаенеудачи вызов возвращает -1.6.3.3 Открепление разделяемой памяти.#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>int shmdt(char *shmaddr)Данный вызов позволяет отсоединить разделяемую память,ранее присоединенную посредством вызова shmat().Параметр shmaddr - адрес прикрепленной к процессу памяти,который был получен при вызове shmat().114В случае успешного выполнения функция возвращает 0, вслучае неудачи -16.3.4 Управление разделяемой памятью.#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:–скопироватьструктуру,описывающуюуправляющие параметры области памяти по адресу, указанному впараметре bufIPC_STATIPC_SET – заменить структуру, описывающую управляющиепараметры области памяти, на структуру, находящуюся по адресу,указанному в параметре buf.
Выполнить эту операцию можетпроцесс, у которого эффективный идентификатор пользователясовпадает с владельцем или создателем очереди, либо процесс справами привилегированного пользователя, при этом процесс можетизменить только владельца области памяти и права доступа к ней.IPC_RMID – удалить очередь. Как уже говорилось, удалитьочередь может только процесс, у которого эффективныйидентификатор пользователя совпадает с владельцем или создателемочереди, либо процесс с правами привилегированного пользователя.SHM_LOCK, SHM_UNLOCK – блокировать или разблокироватьобласть памяти.
Выполнить эту операцию может только процесс справами привилегированного пользователя.115Пример 26. Общая схема работы с общей памятью врамках одного процесса.#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>int putm(char *);int waitprocess(void);int main(int argc, char **argv){key_t key;int shmid;char *shmaddr;key = ftok(“/tmp/ter”,’S’);shmid = shmget(key, 100, 0666|IPC_CREAT);shmaddr = shmat(shmid, NULL, 0); /* подключениек памяти */putm(shmaddr); /* работа с ресурсом */waitprocess();shmctl(shmid,IPC_RMID,NULL);ресурса *//*уничтожениеreturn 0;}В данном примере считается, что putm() и waitprocess() –некие пользовательские функции, определенные в другом месте6.4 Семафоры.Семафоры представляют собой одну из форм IPC и, какправило, используются для синхронизации доступа несколькихпроцессов к разделяемым ресурсам, так как сами по себе другиесредства IPC не предоставляют механизма синхронизации.116Как уже говорилось, семафор представляет собой особый видчисловой переменной, над которой определены две неделимыеоперации: уменьшение ее значения с возможным блокированиемпроцесса и увеличение значения с возможным разблокированиемодного из ранее заблокированных процессов.
Объект System V IPCпредставляет собой набор семафоров. Как правило, использованиесемафоров в качестве средства синхронизации доступа к другимразделяемым объектам предполагает следующую схему:- с каждым разделяемым ресурсом связывается одинсемафор из набора;- положительноезначениесемафораозначаетвозможность доступа к ресурсу (ресурс свободен),неположительное – отказ в доступе (ресурс занят);- перед тем как обратиться к ресурсу, процессуменьшаетзначениесоответствующегоемусемафора, при этом, если значение семафора послеуменьшения должно оказаться отрицательным, топроцесс будет заблокирован до тех пор, пока семафорне примет такое значение, чтобы при уменьшении егозначение оставалось неотрицательным;- закончив работу с ресурсом, процесс увеличиваетзначение семафора (при этом разблокируется один изранее заблокированных процессов, ожидающихувеличения значения семафора, если таковыеимеются);- в случае реализации взаимного исключенияиспользуется двоичный семафор, т.е.
такой, что онможет принимать только значения 0 и 1: такойсемафор всегда разрешает доступ к ресурсу не болеечем одному процессу одновременноРассмотрим набор вызовов для оперирования с семафорами вUNIX System V.6.4.1 Доступ к семафоруДля получения доступа к массиву семафоров (или егосоздания) используется системный вызов:#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>int semget (key_t key, int nsems, int semflag);117Первый параметр функции semget() – ключ для доступа кразделяемому ресурсу, второй - количество семафоров всоздаваемом наборе (длина массива семафоров) и третий параметр –флаги, управляющие поведением вызова. Подробнее процесссоздания разделяемого ресурса описан выше.
Отметим семантикуправ доступа к такому типу разделяемых ресурсов, как семафоры:процесс, имеющий право доступа к массиву семафоров по чтению,может проверять значение семафоров; процесс, имеющий праводоступа по записи, может как проверять, так и изменять значениясемафоров.В случае, если среди флагов указан IPC_CREAT, аргументnsems должен представлять собой положительное число, если жеэтот флаг не указан, значение nsems игнорируется. Отметим, что взаголовочном файле <sys/sem.h> определена константа SEMMSL,задающая максимально возможное число семафоров в наборе. Еслизначение аргумента nsems больше этого значения, вызов semget()завершится неудачно.В случае успеха вызов semget() возвращает положительныйдескриптор созданного разделяемого ресурса, в случае неудачи -1.6.4.2 Операции над семафоромИспользуя полученный дескриптор, можнопроизводитьизменять значения одного или нескольких семафоров в наборе, атакже проверять их значения на равенство нулю,для чегоиспользуется системный вызов semop():#include <sys/types.h>#include<sys/ipc.h>#include<sys/sem.h>int semop (int semid, struct sembuf *semop, size_tnops)Этому вызову передаются следующие аргументы:semid – дескриптор массива семафоров;semop – массив из объектов типа struct sembuf, каждый изкоторых задает одну операцию над семафором;nops – длина массива semop.
Количество семафоров, надкоторыми процесс может одновременно производить операцию водном вызове semop(), ограничено константой SEMOPM, описанной вфайле <sys/sem.h>. Если процесс попытается вызвать semop() с118параметром nops, большим этого значения, этот вызов вернетнеуспех.Структура имеет sembuf вид:struct sembuf {short sem_num;/* номер семафора в векторе */short sem_op;/* производимая операция */short sem_flg;/* флаги операции */}Поле операции в структуре интерпретируется следующимобразом:Пусть значение семафора с номером 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, которыйпредписывает соответствующей операции над семафором не119блокировать процесс, а сразу возвращать управление из вызоваsemop(). Вызов semop() в такой ситуации вернет –1. Кроме того, вэтом поле может быть установлен флаг SEM_UNDO, в этом случаесистема запомнит изменение значения семафора, произведенныеданным вызовом, и по завершении процесса автоматическиликвидирует это изменение. Это предохраняет от ситуации, когдапроцесс уменьшил значение семафора, начав работать с ресурсом, апотом, не увеличив значение семафора обратно, по какой-либопричине завершился. В этом случае остальные процессы, ждущиедоступа к ресурсу, оказались бы заблокированы навечно.6.4.3 Управление массивом семафоров.#include <sys/types.h>#include<sys/ipc.h>#include<sys/sem.h>int semctl (int semid, int num, int cmd, union semunarg)С помощью этого системного вызова можно запрашивать иизменять управляющие параметры разделяемого ресурса, а такжеудалять его.Первый параметр вызова – дескриптор массива семафоров.Параметр num представляет собой индекс семафора в массиве,параметр cmd задает операцию, которая должна быть выполнена надданным семафором.
Последний аргумент имеет тип union semun ииспользуется для считывания или задания управляющих параметроводного семафора или всего массива, в зависимости от значенияаргумента cmd. Тип данных union semun определен в файле<sys/sem.h> и выглядит следующим образом:union semun {int val;// значение одного семафораstruct semid_ds *buf;семафоров в целом *//* параметры массиваushortсемафоров *//* массив значений*array;}где struct semid_ds – структура, описанная в том же файле,в полях которой хранится информация о всем наборе семафоров вцелом, а именно, количество семафоров в наборе, права доступа кнему и статистика доступа к массиву семафоров.120Приведем некоторые наиболее часто используемые значенияаргумента cmd:IPC_STAT – скопировать управляющие параметры наборасемафоров по адресу arg.buf– заменить управляющие параметры наборасемафоров на те, которые указаны в arg.buf.
Чтобы выполнить этуоперацию, процесс должен быть владельцем или создателем массивасемафоров,либообладатьправамипривилегированногопользователя, при этом процесс может изменить только владельцамассива семафоров и права доступа к нему.IPC_SETIPC_RMID – удалить массив семафоров. Чтобы выполнить этуоперацию, процесс должен быть владельцем или создателем массивасемафоров,либообладатьправамипривилегированногопользователя– считать / установить значения всехсемафоров в массив, на который указывает arg.arrayGETALL,SETALLGETVAL – возвратить значение семафора с номером num.Последний аргумент вызова игнорируется.SETVAL – установить значение семафора с номером numравным arg.valВ случае успешного завершения вызов возвращает значение,соответствующее конкретной выполнявшейся операции (0, если неоговорено иное), в случае неудачи – -1.Пример 27.
Работасразделяемойсинхронизацией семафорами.памятьюсПрограмма будет оперировать с разделяемой памятью.1 процесс – создает ресурсы “разделяемая память” и“семафоры”, далее он начинает принимать строки со стандартноговвода и записывает их в разделяемую память.2 процесс – читает строки из разделяемой памяти.Таким образом мы имеем критический участок в момент,когда один процесс еще не дописал строку, а другой ее уже читает.Поэтому следует установить некоторые синхронизации и задержки.1й процесс:#include <stdio.h>#include <sys/types.h>121#include <sys/ipc.h>#include <sys/sem.h>#include <string.h>#define NMAX256int main(int argc, char **argv){key_t key;int semid, shmid;struct sembuf sops;char *shmaddr;char str[NMAX];key = ftok(“/usr/ter/exmpl”, ’S’);/* создаем уникальный ключ */semid = semget(key, 1, 0666 | IPC_CREAT);/* создаем один семафор с определенными правамидоступа */shmid = shmget(key, NMAX, 0666 | IPC_CREAT);/* создаем разделяемую память на 256 элементов*/shmaddr = shmat(shmid, NULL, 0);/* подключаемся к разделу памяти, в shaddr –указатель на буфер с разделяемой памятью */semctl(semid,0,SETVAL, (int) 0);/* инициализируем семафор значением 0 */sops.sem_num = 0;sops.sem_flg = 0;do { /* запуск цикла */printf(“Введите строку:”);if (fgets(str, NMAX, stdin) == NULL){/* окончание ввода *//* пишем признак завершения – строку“Q” */strcpy(str, “Q”);}122/* в текущий момент семафор открыт дляэтого процесса */strcpy(shmaddr, str); /* копируем строку вразд.