Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

Int msgget (key_t key, int msgflag)




где key – ключ

msgflag – флаги, управляющие поведением вызова

 

 

В случае успеха вызов возвращает положительный дескриптор очереди, который может в дальнейшем использоваться для операций с ней, в случае неудачи -1.

 

2)

Отправка сообщения.

#include <sys/types.h>

 

#include <sys/ipc.h>

 

#include <sys/msg.h>

int msgsnd (int msqid, const void *msgp, size_t msgsz, int msgflg)

где msqid – идентификатор очереди, полученный в результате вызова msgget()

msgp – указатель на буфер следующей структуры:

long msgtype -тип сообщения

char msgtext[ ] -данные (тело сообщения)

msgsz -предельный размер сообщения (буфера).

В заголовочном файле <sys/msg.h> определена константа MSGMAX, описывающая максимальный размер тела сообщения. При попытке отправить сообщение, у которого число элементов в массиве msgtext превышает это значение, системный вызов вернет –1.

msgflg - может принимать значения 0 или IPC_NOWAIT. В случае отсутствия флага IPC_NOWAIT вызывающий процесс будет блокирован (т.е. приостановит работу), если для посылки сообщения недостаточно системных ресурсов, т.е. если полная длина сообщений в очереди будет больше максимально допустимого. Если же флаг IPC_NOWAIT будет установлен, то в такой ситуации выход из вызова произойдет немедленно, и возвращаемое значение будет равно –1.

В случае удачной записи возвращаемое значение вызова равно 0.

 

 

3)

Получение сообщения.

#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)

 

где -

Первые три аргумента аналогичны аргументам предыдущего вызова

msgtyp указывает тип сообщения, которое процесс желает получить. Если значение этого аргумента есть 0, то будет получено сообщение любого типа. Если значение аргумента msgtyp больше 0, из очереди будет извлечено сообщение указанного типа. Если же значение аргумента msgtyp отрицательно, то тип принимаемого сообщения определяется как наименьшее значение среди типов, которые меньше модуля msgtyp. В любом случае, как уже говорилось, из подочереди с заданным типом (или из общей очереди, если тип не задан) будет выбрано самое старое сообщение.

 

 

msgflg - комбинация (побитовое сложение) флагов. Если среди флагов не указан IPC_NOWAIT, и в очереди не найдено ни одного сообщения, удовлетворяющего критериям выбора, процесс будет заблокирован до появления такого сообщения. (Однако, если такое сообщение существует, но его длина превышает указанную в аргументе msgsz, то процесс заблокирован не будет, и вызов сразу вернет –1. Сообщение при этом останется в очереди). Если же флаг IPC_NOWAIT указан, то вызов сразу вернет –1.

Процесс может также указать флаг MSG_NOERROR – в этом случае он может прочитать сообщение, даже если его длина превышает указанную емкость буфера. В этом случае в буфер будет записано первые msgsz байт из тела сообщения, а остальные данные отбрасываются.

В случае удачного чтения возвращаемое значение вызова равно 0.

 

4)

 

Управление очередью сообщений.

#include <sys/types.h>

 

#include <sys/ipc.h>

 

#include <sys/msg.h>

int msgctl (int msqid, int cmd, struct msgid_ds *buf)

Где msqid -

идентификатор ресурса,

cmd - команда, которую необходимо выполнить. Возможные значения:

IPC_STAT – скопировать структуру, описывающую управляющие параметры очереди по адресу, указанному в параметре buf

IPC_SET – заменить структуру, описывающую управляющие параметры очереди, на структуру, находящуюся по адресу, указанному в параметре buf

IPC_RMID – удалить очередь. Как уже говорилось, удалить очередь может только процесс, у которого эффективный идентификатор пользователя совпадает с владельцем или создателем очереди, либо процесс с правами привилегированного пользователя.

*buf -структура, описывающая управляющие параметры очереди. Тип msgid_ds описан в заголовочном файле <sys/message.h>, и представляет собой структуру, в полях которой хранятся права доступа к очереди, статистика обращений к очереди, ее размер и т.п.

 

Данный вызов используется для получения или изменения процессом управляющих параметров, связанных с очередью и уничтожения очереди.

 

Рассмотрим пример.

Напишем программу: первый процесс будет читать некоторую текстовую строку из стандартного ввода и в случае, если строка начинается с буквы '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()

{

key_t key; int msgid; char str[256];

key=ftok("/usr/mash",'s');

// получаем ключ, однозначно определяющий доступ к ресурсу данного типа

msgid=msgget(key, 0666 | IPC_CREAT);

// создаем очередь сообщений, 0666 определяет права доступа

for(;;)

{ //запускаем вечный цикл

gets(str); // читаем из стандартного ввода строку

strcpy(Message.Data, str); // и копируем ее в буфер сообщения

switch(str[0])

{

case 'a':

case 'A': Message.mtype=1;//устанавливаем тип, посылаем сообщение в очередь

msgsnd(msgid, (struct msgbuf*) (&Message), strlen(str)+1, 0);

break;

case 'b':

case 'B': Message.mtype=2;

msgsnd(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);

exit(0);

default: exit(0);

}

}

}

Процесс-приемник А

// процесс В аналогичен с точностью до четвертого параметра в msgrcv

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/message.h>

#include <stdio.h>

struct {long mtype;

char Data[256];

} Message;

 

int main()

{

key_t key; int msgid;

key=ftok("/usr/mash",'s'); // получаем ключ по тем же параметрам

msgid=msgget(key, 0666 | IPC_CREAT); //создаем очередь сообщений

for(;;)

{ // запускаем вечный цикл

msgrcv(msgid, (struct msgbuf*) (&Message), 256, 1, 0);

// читаем сообщение с типом

if (Message.Data[0]='q' || Message.Data[0]='Q') exit(0);

printf("%s",Message.Data);

}

exit(0);

}

 

IPC: разделяемая память.

 

 

Механизм разделяемой памяти позволяет нескольким процессам получить отображение некоторых страниц из своей виртуальной памяти на общую область физической памяти. Благодаря этому, данные, находящиеся в этой области памяти, будут доступны для чтения и модификации всем процессам, подключившимся к данной области памяти.

Процесс, подключившийся к разделяемой памяти, может затем получить указатель на некоторый адрес в своем виртуальном адресном пространстве, соответствующий данной области разделяемой памяти. После этого он может работать с этой областью памяти аналогично тому, как если бы она была выделена динамически (например, путем обращения к malloc()), однако, как уже говорилось, разделяемая область памяти не уничтожается автоматически даже после того, как процесс, создавший или использовавший ее, перестанет с ней работать.

 

Рассмотрим набор системных вызовов для работы с разделяемой памятью.

1) Создание общей памяти.

 

#include <sys/types.h>

 

#include <sys/ipc.h>

 

#include <sys/shm.h>

int shmget (key_t key, int size, int shmemflg)

где

ultulu key - ключ для доступа к разделяемой памяти;

size задает размер области памяти, к которой процесс желает получить доступ. Если в результате вызова shmget() будет создана новая область разделяемой памяти, то ее размер будет соответствовать значению size. Если же процесс подключается к существующей области разделяемой памяти, то значение size должно быть не более ее размера, иначе вызов вернет –1. Заметим, что если процесс при подключении к существующей области разделяемой памяти указал в аргументе size значение, меньшее ее фактического размера, то впоследствии он сможет получить доступ только к первым size байтам этой области.

shmemflg определяет флаги, управляющие поведением вызова.

В случае успешного завершения вызов возвращает положительное число – дескриптор области памяти, в случае неудачи - -1.

 

2) Доступ к разделяемой памяти.

 

#include <sys/types.h>

 

#include <sys/ipc.h>

 

#include <sys/shm.h>

 

char *shmat(int shmid, char *shmaddr, int shmflg)

 

где в shmid указан дескриптор.

При помощи этого вызова процесс подсоединяет область разделяемой памяти, дескриптор которой указан в shmid, к своему виртуальному адресному пространству. После выполнения этой операции процесс сможет читать и модифицировать данные, находящиеся в области разделяемой памяти, адресуя ее как любую другую область в своем собственном виртуальном адресном пространстве.

*shmaddr виртуальный адрес в адресном пространстве, начиная с которого необходимо подсоединить разделяемую память. Чаще всего, однако, в качестве значения этого аргумента передается 0, что означает, что система сама может выбрать адрес начала разделяемой памяти. Передача конкретного адреса в этом параметре имеет смысл в том случае, если, к примеру, в разделяемую память записываются указатели на нее же (например, в ней хранится связанный список) – в этой ситуации для того, чтобы использование этих указателей имело смысл и было корректным для всех процессов, подключенных к памяти, важно, чтобы во всех процессах адрес начала области разделяемой памяти совпадал.

Shmflg -комбинация флагов. В качестве значения этого аргумента может быть указан флаг SHM_RDONLY, который указывает на то, что подсоединяемая область будет использоваться только для чтения.

 

Эта функция возвращает адрес, начиная с которого будет отображаться присоединяемая разделяемая память. В случае неудачи вызов возвращает -1.

 

2)

 

Открепление разделяемой памяти.

 

#include <sys/types.h>

 

#include <sys/ipc.h>

 

#include <sys/shm.h>

int shmdt(char *shmaddr)

 

Где shmaddr - адрес прикрепленной к процессу памяти, который был получен при вызове shmat()

Данный вызов позволяет отсоединить разделяемую память, ранее присоединенную посредством вызова shmat()

В случае успешного выполнения функция возвращает 0, в случае неудачи -1

 

3)

Управление разделяемой памятью.

 

#include <sys/types.h>

 

#include <sys/ipc.h>

 

#include <sys/shm.h>

int shmctl(int shmid, int cmd, struct shmid_ds *buf)

где -

Shmid -

дескриптор области памяти, команда, которую необходимо выполнить, и структура, описывающая управляющие параметры области памяти.

cmd – команда. Возможные значения аргумента cmd:

IPC_STAT – скопировать структуру, описывающую управляющие параметры области памяти по адресу, указанному в параметре buf.

 

IPC_SET – заменить структуру, описывающую управляющие параметры области памяти, на структуру, находящуюся по адресу, указанному в параметре buf. Выполнить эту операцию может процесс, у которого эффективный идентификатор пользователя совпадает с владельцем или создателем очереди, либо процесс с правами привилегированного пользователя, при этом процесс может изменить только владельца области памяти и права доступа к ней.

IPC_RMID – удалить очередь. Как уже говорилось, удалить очередь может только процесс, у которого эффективный идентификатор пользователя совпадает с владельцем или создателем очереди, либо процесс с правами привилегированного пользователя.

SHM_LOCK, SHM_UNLOCK – блокировать или разблокировать область памяти. Выполнить эту операцию может только процесс с правами привилегированного пользователя.

 

Данный вызов используется для получения или изменения процессом управляющих параметров, связанных с областью разделяемой памяти, наложения и снятия блокировки на нее и ее уничтожения.

 

 

Пример. Работа с общей памятью в рамках одного процесса.

 

int main(int argc, chr **argv)

 

{

 

key_t key;

 

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); /*уничтожение ресурса*/

 

exit();

 

}

 

Массив семафоров

Семафоры используются для синхронизации доступа нескольких процессов к разделяемым ресурсам, т.е. фактически они разрешают или запрещают процессу использование разделяемого ресурса. В начале излагалась идея использования такого механизма. Речь шла о том, что при наличии некоторого разделяемого ресурса, с которым один из процессов работает, необходимо блокировать доступ к нему других процессов. Для этого с ресурсом связывается некоторая переменная-счетчик, доступная для всех процессов. При этом считаем, что значение счетчика, равное 1 будет означать доступность ресурса, а значение, равное 0 — его занятость. Далее работа организуется следующим образом: процесс, которому необходим доступ к файлу, проверяет значение счетчика, если оно равно 0, то он в цикле ожидает освобождения ресурса, если же оно равно 1, процесс устанавливает значение счетчика равным 0 и работает с ресурсом. После завершения работы необходимо открыть доступ к ресурсу другим процессам, поэтому снова сбрасывается значение счетчика на 1. В данном примере счетчик и есть семафор.

Семафор находится адресном пространстве ядра, и все операции выполняются также в режиме ядра.

В System V IPC семафор представляет собой группу (вектор) счетчиков, значения которых могут быть произвольными в пределах, определенных системой (не только 0 и 1).

 

1) Доступ к семафору

#include <sys/types.h>

 

#include<sys/ipc.h>

 

#include<sys/sem.h>

Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...