Курынин Р.В., Машечкин И.В., Терехин А.Н. - Конспект лекций по ОС (1114685), страница 37
Текст из файла (страница 37)
Но функциональная структура идентична. В частности,среди этих наборов можно выделить функции, имеющие суффикс get (а префиксная частьпредставляет собою аббревиатуру имени ресурса). Среди параметров данных функцийприсутствует ключ, о котором шла речь в начале выше, а также некоторые флаги. Соответственно,эти функции в зависимости от флагов позволяют создавать или подключаться к существующемуресурсу IPC, ассоциированному с указываемым ключом.<ResourceName>get(key, ..., flags);Параметр флаги (flags) является один из важных параметров. Он может быть комбинациейразличных флагов.
Основные из них приведены ниже.− IPC_PRIVATE — данный флаг определяет создание IPC-ресурса, не доступного остальнымпроцессам. Т.е. функция get при наличии данного флага всегда открывает новый ресурс, ккоторому никто другой не может подключиться. Данный флаг позволяет использоватьразделяемый ресурс между родственными процессами (поскольку дескриптор созданногоресурса передается при наследовании дочерним процессам).− IPC_CREAT — если данного флага нет среди параметров функции get, то это означает, чтопроцесс хочет подключиться к существующему ресурсу. В этом случае, если такой ресурссуществует, и права доступа к нему позволяют к нему обратиться, то процесс получитдескриптор ресурса и продолжит работу.
Иначе функция get вернет -1, а переменная errnoбудет содержать код ошибки. Если же при вызове функции get данный флаг установлен, тофункция работает на создание или подключение к существующему ресурсу. В данном случаевозможно возникновение ошибки из-за нехватки прав доступа в случае существованияресурса. Но при установленном флаге встает вопрос, кто является владельцем ресурса, и,соответственно, кто его должен удалять (поскольку каждый процесс либо подключается ксуществующему ресурсу, либо создает новый). Для разрешения данной проблемыиспользуется следующий флаг.− IPC_EXCL — используя данный флаг в паре с флагом IPC_CREAT, функция get будетработать только на создание нового ресурса.
Если же ресурс будет уже существовать, тофункция get вернет -1, а переменная errno будет содержать код соответствующей ошибки.Ниже приводится список некоторых ошибок, возможных при вызове функции get,возвращаемых в переменной errno:− ENOENT — ресурс не существует, и не указан флаг IPC_CREAT;− EEXIST — ресурс существует, и установлены флаги IPC_CREAT | IPC_EXCL;− EACCESS — не хватает прав доступа на подключение.1433.2.1Очередь сообщений IPCСистема предоставляет возможность создания некоторого функционально расширенногоаналога канала, но главное отличие заключается в том, что сообщения в очереди сообщений IPCтипизированы.
Каждое сообщение помимо содержательной своей части имеет атрибут типсообщения. Тогда очередь сообщений можно рассматривать с двух позиций: во-первых, каксквозную очередь (когда тип сообщения не важен, они все находятся в единой очереди), а, вовторых, как суперпозицию очередей однотипных сообщений (3.2.1). При этом способинтерпретации допускает одновременно различные типы интерпретации. Непосредственныйвыбор интерпретации определяется в момент считывания сообщения из очереди.BAABABAРис. 90.Очередь сообщений IPC.Для организации работы с очередью предусмотрен набор функций. Во-первых, это ужеупомянутая функция создания/доступа к очереди сообщений.#include <sys/types.h>#include <sys/ipc.h>#include <sys/message.h>int msgget(key_t key, int msgflag);У данной функции два параметра: ключ и флаги.
В случае успешного выполнения функциявозвращает положительный дескриптор очереди, иначе возвращается -1.Существует блок функций использования очереди: в частности, функции отправки иприема сообщения. Сначала рассмотрим функцию отправки сообщений.#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>int msgsnd(int msqid, const void *msgp, size_t msgsz,int msgflg);Первый аргумент данной функции — идентификатор очереди, полученный в результатевызова msgget(). Второй аргумент — указатель на буфер, содержащий реальные данные и типсообщения, подлежащего посылке в очередь, в третьем аргументе указывается размер буфера. Вкачестве буфера необходимо указывать структуру, содержащую следующие поля:− long msgtype — тип сообщения (только положительное длинное целое);− char msgtext[] — данные (тело сообщения).144Последний аргумент функции — это флаги.
Среди разнообразных флагов можно выделитьте, которые определяют режим блокировки при отправке сообщения. Если флаг равен 0, то вызовбудет блокироваться, если для отправки недостаточно системных ресурсов. Можно установитьфлаг IPC_NOWAIT, который позволяет работать без блокировки: тогда в случае возникновенияошибки при отправке сообщения, вызов вернет -1, а переменная errno будет содержатьсоответствующий код ошибки.Для получения сообщений используется функция msgrcv().#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>int msgrcv(int msqid, void *msgp, size_t msgsz,long msgtyp, int msgflg);Первые три аргумента аналогичны аргументам предыдущего вызова: дескриптор очереди,указатель на буфер, куда следует поместить данные, и максимальный размер (в байтах) теласообщения, которое можно туда поместить. Буфер, используемый для приема сообщения, должениметь структуру, описанную выше.Четвертый аргумент указывает тип сообщения, которое процесс желает получить.
Еслизначение этого аргумента есть 0, то будет получено сообщение любого типа (т.е. идет работа сосквозной очередью). Если значение аргумента msgtyp больше 0, из очереди будет извлеченосообщение указанного типа. Если же значение аргумента msgtyp отрицательно, то типпринимаемого сообщения определяется как наименьшее значение среди типов, которые меньшемодуля msgtyp. В любом случае, как уже говорилось, из подочереди с заданным типом (или изобщей очереди, если тип не задан) будет выбрано самое старое сообщение.Последним аргументом является комбинация (побитовое сложение) флагов.
Если средифлагов не указан IPC_NOWAIT, и в очереди не найдено ни одного сообщения, удовлетворяющегокритериям выбора, процесс будет заблокирован до появления такого сообщения. (Однако, еслитакое сообщение существует, но его длина превышает указанную в аргументе msgsz, то процессзаблокирован не будет, и вызов сразу вернет -1; сообщение при этом останется в очереди). Еслиже флаг IPC_NOWAIT указан, и в очереди нет ни одного необходимого сообщения, то вызов сразувернет -1.Процесс может также указать флаг MSG_NOERROR: в этом случае он может прочитатьсообщение, даже если его длина превышает указанную емкость буфера. Тогда в буфер будетзаписано первые msgsz байт из тела сообщения, а остальные данные отбрасываются.В случае успешного завершения функция возвращает количество успешно прочитанныхбайтов в теле сообщения.Следующая группа функций — это функции управления ресурсом.
Эти функцииобеспечивают в общем случае изменение режима функционирования ресурса, в т.ч. и удалениересурса.#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>145int msgctl(int msqid, int cmd, struct msgid_ds *buf);Данная функция используется для получения или изменения управляющих параметров,связанных с очередью, и уничтожения очереди. Ее аргументы — идентификатор ресурса, команда,которую необходимо выполнить, и структура, описывающая управляющие параметры очереди.Тип msgid_ds представляет собой структуру, в полях которой хранятся права доступа к очереди,статистика обращений к очереди, ее размер и т.п.Возможные значения аргумента cmd:− IPC_STAT — скопировать структуру, описывающую управляющие параметры очереди поадресу, указанному в параметре buf;− IPC_SET — заменить структуру, описывающую управляющие параметры очереди, наструктуру, находящуюся по адресу, указанному в параметре buf;− IPC_RMID — удалить очередь.Пример.
Использование очереди сообщений. В приведенном ниже примере участвуюттри процесса: основной процесс и процессы A и B. Основной процесс считывает из стандартноговвода текстовую строку. Если она начинается на букву A, то эта строка посылается процессу A,если на B — то процессу B, если на Q — то обоим процессам (в этом случае основной процессждет некоторое время, затем удаляет очередь сообщений и завершается). Процессы A и Bсчитывают из очереди адресуемые им сообщения и распечатывают их на экране.
Если пришедшеесообщение начинается с буквы Q, то процесс завершается./* ОСНОВНОЙ ПРОЦЕСС */#include <sys/types.h>#include <sys/ipc.h>#include <sys/message.h>#include <stdio.h>/* декларация структуры сообщения */struct{long mtype;/* тип сообщения */char Data[256];/* сообщение */} Message;int main(int argc, char **argv){key_t key;int msgid;char str[256];146/*получаем уникальный ключ, однозначно определяющийдоступ к ресурсу данного типа */key = ftok("/usr/mash",'s');/* создаем новую очередь сообщений,0666 определяет права доступа */msgid = msgget(key, 0666 | IPC_CREAT | IPC_EXCL);/* запускаем вечный цикл */for(;;){gets(str); /* читаем из стандартного ввода строку *//* и копируем ее в буфер сообщения */strcpy(Message.Data, str);/* анализируем первый символ прочитанной строки */switch(str[0]){case 'a':case 'A':/* устанавливаем тип 1 для ПРОЦЕССА A*/Message.mtype = 1;/* посылаем сообщение в очередь */msgsnd(msgid, (struct msgbuf*) (&Message),strlen(str)+1, 0);break;case 'b':case 'B':/* устанавливаем тип 2 для ПРОЦЕССА A*/Message.mtype = 2;147msgsnd(msgid, (struct msgbuf*) (&Message),strlen(str)+1, 0);break;case 'q':case 'Q':Message.mtype = 1;msgsnd(msgid, (struct msgbuf*) (&Message),strlen(str)+1, 0);Message.mtype = 2;msgsnd(msgid, (struct msgbuf*) (&Message),strlen(str)+1, 0);/* ждем получения сообщенийпроцессами А и В */sleep(10);2/* уничтожаем очередь */msgctl(msgid, IPC_RMID, NULL);exit(0);default:/* игнорируем остальные случаи */break;}}}/* ПРИНИМАЮЩИЙ ПРОЦЕСС A (процесс B будет аналогичным) */#include <sys/types.h>#include <sys/ipc.h>2В данном случае это решение не совсем корректно, поскольку делается предположение, что процессы A и Bза 10 единиц времени должны получить последние сообщения.