Курынин Р.В., Машечкин И.В., Терехин А.Н. - Конспект лекций по ОС (1114685), страница 39
Текст из файла (страница 39)
И с этим указателем можно работать стандартнымисредствами языка C. В случае неудачи вызов возвращает -1.Соответственно, для открепления разделяемой памяти от адресного пространства процессаиспользуется функция shmdt().#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>int shmdt(char *shmaddr);Данный вызов позволяет отсоединить разделяемую память, ранее присоединеннуюпосредством вызова shmat().
Параметр shmaddr — адрес прикрепленной к процессу памяти,который был получен при вызове 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);Данный вызов используется для получения или изменения процессом управляющихпараметров, связанных с областью разделяемой памяти, наложения и снятия блокировки на нее и154ее уничтожения. Аргументы вызова — дескриптор области памяти, команда, которую необходимовыполнить, и структура, описывающая управляющие параметры области памяти.Возможные значения аргумента cmd:− IPC_STAT — скопировать структуру, описывающую управляющие параметры областипамяти;− IPC_SET — заменить структуру, описывающую управляющие параметры области памяти, наструктуру, находящуюся по адресу, указанному в параметре buf;− IPC_RMID — удалить ресурс;− SHM_LOCK, SHM_UNLOCK — блокировать или разблокировать область памяти.
Этоединственные средства синхронизации в данном ресурсе, их реализация должнаподдерживаться аппаратурой.Пример. Работа с общей памятью в рамках одного процесса. В данном примере процесссоздает ресурс разделяемая память, размером в 100 байт (и соответствующими флагами),присоединяет ее к своему адресному пространству, при этом указатель на начало данной областисохраняется в переменной shmaddr. Дальше процесс производит различные манипуляции, а передсвоим завершением он удаляет данную область разделяемой памяти.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);/* работаем с разделяемой памятью, как с обычной */putm(shmaddr);waitprocess();shmctl(shmid, IPC_RMID, NULL);return 0;}3.2.3Массив семафоров IPCСемафоры представляют собой одну из форм IPC и используются для организациисинхронизации взаимодействующих процессов.
Рассмотрение функций для работы с семафорамимы начнем традиционно с функции создания/доступа к данному ресурсу — функции semget().#include <sys/types.h>#include <sys/ipc.h>155#include <sys/sem.h>int semget(key_t key, int nsems, int semflag);Первый параметр функции semget() — ключ, второй — количество семафоров (длинамассива семафоров), и третий параметр — флаги. Через флаги можно определить права доступа ите операции, которые должны выполняться (открытие семафора, проверка, и т.д.). Функцияsemget() возвращает целочисленный идентификатор созданного разделяемого ресурса, либо -1 вслучае ошибки.
Необходимо отметить, что если процесс подключается к существующему ресурсу,то возможно появление коллизий, связанных с неверным указанием длины массива семафоров.Основная функция для работы с семафорами — функция semop().#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>int semop(int semid, struct sembuf *semop, size_t nops);Первый аргумент — идентификатор ресурса, второй аргумент является указателем наначало массива структур, определяющих операции, которые необходимо произвести надсемафорами.
Третий параметр — количество структур в указанном массиве. Каждый элементданного массива — это структура определенного вида, предназначенная для выполнения операциинад соответствующим семафором в массиве семафоров. Ниже приводится указанная структура.struct sembuf{short sem_num; /* номер семафора в массиве */short sem_op;/* код производимой операции */short sem_flg; /* флаги операции */}Поле операции интерпретируется следующим образом.
Пускай значение семафора сномером num равно val. Тогда порядок работы с семафором можно записать в виде следующейсхемы.Если sem_op = 0 тоесли val ≠ 0 топока (val ≠ 0) [процесс блокирован][возврат из вызова]156Если sem_op ≠ 0 тоесли val + sem_op < 0 топока (val + sem_op < 0) [процесс блокирован]val = val + sem_opПонимать данную последовательность действий надо так. Если код операции равен нулю, азначение данного семафора не равно нулю, то процесс будет блокирован до тех пор, пока значениесемафора не обнулится.
Если же и код операции нулевой, и значение семафора нулевое, тоникаких блокировок не произойдет, и операция завершится. Если код операции отличен от нуля(т.е. процесс желает скорректировать значение семафора), то в этом случае делается следующаяпроверка. Если сумма текущего значения семафора и кода операции отрицательная, то процессбудет блокирован. Как только он разблокируется, происходит коррекция. Замети, что еслиуказанная сумма значения семафора и кода операции неотрицательная, то коррекция происходитбез блокировок.Для управления данным типом разделяемых ресурсов используется системный вызовsemctl().#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>int semctl(int semid, int num, int cmd, union semun arg);Параметрами данной функции являются, соответственно, дескриптор массива семафоров,индекс семафора в массиве, команда и управляющие параметры.
Среди множества команд,которые можно выполнять с помощью данной функции, можно особо отметить две: командуудаления ресурса (IPC_RMID) и команду инициализации и модификации значения семафора(IPC_SET). Используя последнюю команду, можно использовать массив семафоров уже не каксредство синхронизации, а как средство передачи информации между взаимодействующимипроцессами (что само по себе является, как минимум, неэффективным, поскольку семафорысоздавались именно как средства синхронизации).Данная функция возвращает значение, соответствующее выполнявшейся операции (поумолчанию 0), или -1 в случае неудачи.
Ниже приводится определение типа последнегопараметра.<sys/sem.h>union semun{int val;/* значение одного семафора */157struct semid_ds *buf;/* параметры массива семафоров вцелом (количество, права доступа,статистика доступа)*/ushort *array;/* массив значений семафоров */}Пример. Использование разделяемой памяти и семафоров. В рассматриваемом примеремоделируется двухпроцессная система, в которой первый процесс создает ресурсы разделяемаяпамять и массив семафоров.
Затем он начинает читать информацию со стандартного устройстваввода, считанные строки записываются в разделяемую память. Второй процесс читает строки изразделяемой памяти. Данная задача требует синхронизации, которая будет осуществляться наоснове механизма семафоров. Стоит обратить внимание на то, что с одним и тем же ключомодновременно создаются ресурсы двух разных типов (в случае использования ресурсов одноготипа подобные действия некорректны)./* 1-ый процесс */#include <stdio.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>#include <string.h>#define NMAX 256int 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’);/* создаем один семафор с определенными правами доступа */158semid = semget(key, 1, 0666 | IPC_CREAT | IPC_EXCL);/*создаем разделяемую память на 256 элементов */shmid = shmget(key, NMAX, 0666 | IPC_CREAT | IPC_EXCL);/* подключаемся к разделу памяти, в shmaddr – указатель набуфер с разделяемой памятью */shmaddr = shmat(shmid, NULL, 0);/* инициализируем семафор значением 0 */semctl(semid, 0, SETVAL, (int) 0);sops.sem_num = 0;sops.sem_flg = 0;/* запуск цикла */do{printf(“Введите строку:”);if(fgets(str, NMAX, stdin) == NULL)/* пишем признак завершения – строку “Q” */strcpy(str, “Q”);/* в текущий момент семафор открыт для этого процесса*//* копируем строку в разд.
память */strcpy(shmaddr, str);/* предоставляем второму процессу возможность войти */sops.sem_op = 3; /* увеличение семафора на 3 */semop(semid, &sops, 1);/* ждем, пока семафор будет открыт для 1го процесса –для следующей итерации цикла*/sops.sem_op = 0; /* ожидание обнуления семафора */semop(semid, &sops, 1);} while (str[0] != ‘Q’);159/* в данный момент второй процесс уже дочитал изразделяемой памяти и отключился от нее – можно ее удалять*/shmdt(shmaddr); /* отключаемся от разделяемой памяти *//* уничтожаем разделяемую память */shmctl(shmid, IPC_RMID, NULL);/* уничтожаем семафор */semctl(semid, 0, IPC_RMID, (int) 0);return 0;}/* 2-ой процесс */#include <stdio.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>#include <string.h>#define NMAX 256int 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’);160semid = semget(key, 1, 0666);shmid = shmget(key, NMAX, 0666);/* аналогично предыдущему процессу –инициализация ресурсов */shmaddr = shmat(shmid, NULL, 0);sops.sem_num = 0;sops.sem_flg = 0;/* запускаем цикл */do{printf(“Waiting...\n”);/* ожидание на семафоре */sops.sem_op = -2;/* будем ожидать, пока “значение семафора” + ”значениеsem_op” не станет неотрицательным, т.е.
пока значениесемафора не станет, как минимум, 2 (2 - 2 >= 0) */semop(semid, &sops, 1);/* теперь значение семафора равно 1 *//* критическая секция - работа с разделяемой памятью –в этот момент первый процесс к разделяемой памятидоступа не имеет *//* копируем строку из разд. памяти */strcpy(str, shmaddr);if(str[0] == ‘Q’)/* завершение работы - освобождаем разд. память*/shmdt(shmaddr);/* после работы – обнулим семафор */sops.sem_op = -1;161semop(semid, &sops, 1);printf(“Read from shared memory: %s\n”, str);} while (str[0] != ‘Q’);return 0;}3.3Сокеты — унифицированный интерфейспрограммирования распределенных системСредства межпроцессного взаимодействия ОС UNIX, представленные в системе IPC,решают проблему взаимодействия двух процессов, выполняющихся в рамках одной операционнойсистемы.