Н.В. Вдовикина, И.В. Машечкин, А.Н. Терехин, А.Н. Томилин - Операционные системы - взаимодействие процессов (2008) (1114653), страница 18
Текст из файла (страница 18)
В принципе, программист,пишущий программы для работы с разделяемым ресурсом, можетпросто жестко указать в программе некоторое константное значениеключа для именования разделяемого ресурса. Однако, в такомслучае возможна ситуация, когда к моменту запуска такойпрограммы в системе уже существует разделяемый ресурс с такимзначением ключа, и в виду того, что ключи должны бытьуникальными во всей системе, попытка породить второй ресурс стаким же ключом закончится неудачей (подробнее этот моментбудет рассмотрен ниже).5.1.2 Генерация ключей: функция ftok()Как видно, встает проблема именования разделяемого ресурса:необходим некий механизм получения заведомо уникального ключадля именования ресурса, но вместе с тем нужно, чтобы этотмеханизм позволял всем процессам, желающим работать с однимресурсом, получить одно и то же значение ключа.Для решения этой задачи служит функция ftok():#include <sys/types.h>#include <sys/ipc.h>key_t ftok(char *filename, int proj);Эта функция генерирует значение ключа по путевому именинекоторого существующего файла и добавочному целому,передаваемым в качестве параметров.
Она использует для созданиязначения ключа номер индексного дескриптора указанного файла иинформацию о файловой системе, в которой он находится. еслифайл с указанным именем не существует или недоступенвызывающеу процессу, функция возвращает -1. Гарантируется, что106при повторном запуске ftok() с теми же параметрами будетполучено то же самое значение ключа18. Предполагается, чтопередаваемое путевое имя файла известно всем процессамвызывающей программы и имеет в рамках ее некоторый смысл(например, это может быть имя демона-сервера, имя файла данныхиспользуемого сервером и т.п.).Смысл же второго аргумента функции ftok() – добавочногоцелого – в том, что он позволяет генерировать разные значенияключа по одному и тому же значению первого параметра – именифайла.
Тем самым, используя одно и то же путевое имя, можнополучить несколько ключей, если нам требуется доступ кнескольким различным ресурсам в рамках одной и той жепроuраммы. Кроме того, это позволяет программисту поддерживатьнесколько версий своей программы, которые будут использоватьодно и то же имя файла, но разные добавочные параметры длягенерации ключа, и тем самым получат возможность в рамках однойсистемы работать с разными разделяемыми ресурсами.Следует заметить, что функция ftok() не является системнымвызовом, а предоставляется библиотекой.5.1.3 Общие принципы работы с разделяемыми ресурсамиРассмотрим некоторые моменты, общие для работы со всемиразделяемыми ресурсами IPC.
Как уже говорилось, общим для всехресурсов является механизм именования. Кроме того, для каждогоIPC-ресурса поддерживается идентификатор его владельца иструктура, описывающая права доступа к нему. Подобно файлам,права доступа задаются отдельно для владельца, его группы и всехостальных пользователей; однако, в отличие от файлов, дляразделяемых ресурсов поддерживается только две категориидоступа: по чтению и записи. Априори считается, что возможностьизменять свойства ресурса и удалять его имеется только у процесса,эффективный идентификатор пользователя которого совпадает сидентификатором владельца ресурса. Владельцем ресурсаназначается пользователь, от имени которого выполнялся процесс,создавший ресурс, однако создатель может передать прававладельца другому пользователю. В заголовочном файле<sys/ipc.h> определен тип struct ipc_perm, который описываетправа доступа к любому IPC-ресурсу.
Поля в этой структуре18при условии, что указанный файл между двумя обращениями к ftok() не удалялся и непересоздавался заново, т.к. при этом он получит другой номер индексного дескриптора107содержат информацию о создателе и владельце ресурса и ихгруппах, правах доступа к ресурсу и его ключе.Для создания разделяемого ресурса с заданным ключом, либоподключения к уже существующему ресурсу с таким ключомиспользуются ряд системных вызовов, имеющих общий суффиксget. Общими параметрами для всех этих вызовов являются ключ ифлаги.
В качестве значения ключа при создании любого IPC-объектаможет быть указано значение IPC_PRIVATE. При этом создаетсяресурс, который будет доступен только породившему его процессу.Такие ресурсы обычно порождаются родительским процессом,который затем сохраняет полученный дескриптор в некоторойпеременной и порождает своих потомков. Так как потомкамдоступен уже готовый дескриптор созданного объекта, они могутнепосредственно работать с ним, не обращаясь предварительно к«get»-методу.
Таким образом, созданный ресурс может совместноиспользоваться родительским и порожденными процессами. Однако,важно понимать, что если один из этих процессов повторно вызовет«get»-метод с ключом IPC_PRIVATE, в результате будет получендругой, совершенно новый разделяемый ресурс, так как приобращении к «get»-методу с ключом IPC_PRIVATE всякий разсоздается новый объект нужного типа19.Если при обращении к «get»-методу указан ключ, отличныйот IPC_PRIVATE, происходит следующее: Происходит поиск объекта с заданным ключом среди ужесуществующих объектов нужного типа.
Если объект суказанным ключом не найден, и среди флагов указан флагIPC_CREAT, будет создан новый объект. При этом значениепараметра флагов должно содержать побитовое сложениефлага IPC_CREAT и константы, указывающей права доступадля вновь создаваемого объекта. Если объект с заданным ключом не найден, и средипереданных флагов отсутствует флаг IPC_CREAT, «get»метод вернет –1, а в переменной errno будет установленозначение ENOENT Если объект с заданным ключом найден средисуществующих, «get»-метод вернет дескриптор для этогосуществующего объекта, т.е. фактически, в этом случае19гарантируется, что функция ftok() ни при каких значениях своих входныхпараметров не может сгенерировать ключ, совпадающий с IPC_PRIVATE.108происходит подключение к уже существующему объекту позаданному ключу.
Если процесс ожидал создания новогообъекта по указанному ключу, то для него такое поведениеможет оказаться нежелательным, так как это будет означать,что в результате случайного совпадения ключей (например,если процесс не использовал функцию ftok()) онподключился к чужому ресурсу. Чтобы избежать такойситуации, следует указать в параметре флагов наряду сфлагом IPC_CREAT и правами доступа еще и флаг IPC_EXCL– в этом случае «get»-метод вернет -1, если объект с такимключом уже существует (переменная errno будетустановлена в значение EEXIST) Следует отметить, что при подключении к ужесуществующему объекту дополнительно проверяются правадоступа к нему. В случае, если процесс, запросившийдоступ к объекту, не имеет на то прав, «get»-метод вернет–1, а в переменной errno будет установлено значениеEACCESSНужно иметь в виду, что для каждого типа объектов IPCсуществует некое ограничение на максимально возможноеколичество одновременно существующих в системе объектовданного типа.
Если при попытке создания нового объекта окажется,что указанное ограничение превышено, «get»-метод, совершавшийпопытку создания объекта, вернет -1, а в переменной errno будетуказано значение ENOSPC.Отметим, что даже если ни один процесс не подключен кразделяемому ресурсу, система не удаляет его автоматически.Удаление объектов IPC является обязанностью одного изработающих с ним процессов и для этого определена специальнаяфункция. Для этого системой предоставляются соответствующиефункции по управлению объектами System V IPC.5.2 Очередь сообщенийИтак, одним из типов объектов System V IPC являютсяочереди сообщений.
Очередь сообщений представляет собой некоехранилище типизированных сообщений, организованное попринципу FIFO. Любой процесс может помещать новые сообщенияв очередь и извлекать из очереди имеющиеся там сообщения.Каждое сообщение имеет тип, представляющий собой некотороецелое число. Благодаря наличию типов сообщений, очередь можноинтерпретировать двояко — рассматривать ее либо как сквозную109очередь неразличимых по типу сообщений, либо как некотороеобъединение подочередей, каждая из которых содержит элементыопределенного типа. Извлечение сообщений из очереди происходитсогласно принципу FIFO – в порядке их записи, однако процессполучатель может указать, из какой подочереди он хочет извлечьсообщение, или, иначе говоря, сообщение какого типа он желаетполучить – в этом случае из очереди будет извлечено самое «старое»сообщение нужного типа (см.
Рис. 18).ВААВАВАРис. 18 Типизированные очереди сообщенийРассмотрим набор системных вызовов, поддерживающийработу с очередями сообщений.5.2.1 Доступ к очереди сообщенийДля создания новой или для доступа к существующейиспользуется системный вызов:#include <sys/types.h>#include <sys/ipc.h>#include <sys/message.h>int msgget (key_t key, int msgflag);В случае успеха вызов возвращает положительный дескрипторочереди, который может в дальнейшем использоваться для операцийс ней, в случае неудачи -1. Первым аргументом вызова являетсяключ, вторым – флаги, управляющие поведением вызова.
Подробнеедетали процесса создания/подключения к ресурсу описаны выше.5.2.2 Отправка сообщенияДля отправки сообщения используется функция msgsnd():#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>int msgsnd (intmsgsz, int msgflg)msqid,constvoid*msgp,size_tЕе первый аргумент — идентификатор очереди, полученный врезультате вызова msgget(). Второй аргумент — указатель на110буфер, содержащий реальные данные (тело сообщения) и типсообщения, подлежащего посылке в очередь, в третьем аргументеуказывается длина тела сообщения в байтах.Буфер интерпретируется как структура, соответствующаяследующему шаблону:#include <sys/msg.h>struct msgbuf {long msgtype; // тип сообщенияchar msgtext[1]; //данные (тело сообщения)};В реальности такая структура не означает, что теломсообщения обязательно должен быть лишь один символ (и вообщетекст, состоящий из символов).