Система межпроцессного взаимодействия IPC.
Система межпроцессного взаимодействия IPC. Состав. Очереди сообщений Семафоры Разделяемая память
Общие концепции Для именования объекта IPC используется уникальный ключ, по которому процессу возвращается дескриптор объекта Для каждого IPC-ресурса поддерживается идентификатор его владельца и структура, описывающая права доступа к нему (только две категории прав доступа- по чтению и по записи). информацию о создателе и владельце ресурса, их группе его ключ. struct ipc_perm
Общие концепции #include key_t ftok (char *filename, char proj) filename – строка, cодержащая имя файла proj – добавочный символ (может использоваться, например, для поддержания разных версий программы)
Общие концепции get(key,....., flags) - создание/подключение Флаги cоздания/подключения: IPC_PRIVATE (доступность только породившему процессу) IPC_CREAT (создать новый или подключиться к существующему) IPC_EXCL ( + IPC_CREAT создание только нового) Значения переменной errno при ошибках: ENOENT (ресурса нет и не указан флаг IPC_CREAT) EEXIST (ресурс существует и флаги IPC_EXCL | IPC_CREAT) EACCESS (нет прав на подключение) ……..
IPC: очередь сообщений.
Очередь сообщений Организация очереди сообщений по принципу FIFO Использование типов сообщений BAABABA
Создание/доступ к очереди сообщений key – ключ msgflag – флаги, управляющие поведением вызова В случае успеха возвращается положительный дескриптор очереди, в случае неудачи возвращается –1. #include #include #include int msgget (key_t key, int msgflag)
int msgsnd (int msqid, const void *msgp, size_t msgsz, int msgflg) Отправка сообщений msqid– идентификатор очереди, полученный в результате вызова msgget() msgp – указатель на буфер следующей структуры: long msgtype -тип сообщения char msgtext[ ] -данные (тело сообщения) #include
int msgsnd (int msqid, const void *msgp, size_t msgsz, int msgflg) Отправка сообщений msgsz–размер тела сообщения msgflg 0 процесс блокируется, если для посылки сообщения недостаточно системных ресурсов IPC_NOWAIT – работа без блокировки (возврат –1) #include
int msgrcv (int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg) Получение сообщений msqid– идентификатор очереди msgp – указатель на буфер msgsz– размер тела сообщения msgtyp тип сообщения, которое процесс желает получить = 0 любого типа > 0 типа msgtyp < 0 наименьшее значение среди типов, которые меньше модуля msgtyp #include
int msgrcv (int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg) Получение сообщений msgflg– побитовое сложение флагов IPC_NOWAIT – если сообщения в очереди нет, то возврат –1 MSG_NOERROR – разрешение получать сообщение, даже если его длина превышает емкость буфера #include В случае успеха возвращает количество прочитанных байтов в теле сообщения
int msgctl (int msqid, int cmd, struct msgid_ds *buf) Управление очередью сообщений msgid– идентификатор ресурса cmd– команда IPC_STAT – скопировать структуру, описывающую управляющие параметры очереди по адресу, указанному в параметре buf IPC_SET – заменить структуру, описывающую управляющие параметры очереди, на структуру, находящуюся по адресу, указанному в параметре buf IPC_RMID – удалить очередь. #include
int msgctl (int msqid, int cmd, struct msgid_ds *buf) Управление очередью сообщений buf– структура, описывающая параметры очереди. Тип msgid_ds описан в заголовочном файл, и представляет собой структуру, в полях которой хранятся права доступа к очереди, статистика обращений к очереди, ее размер и т.п. #include В случае успеха возвращается 0
Пример. Использование очереди сообщений.
Основной процесс int main(int argc, chr **argv) { key_t key; int msgid; char str[256]; key = ftok("/usr/mash", 's'); msgid = msgget(key, 0666 | IPC_CREAT | IPC_EXCL); for(;;) { gets(str); strcpy(Message.Data, str);... #include struct { long mtype; char Data[256]; } Message;
... 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); sleep(10); msgctl(msgid, IPC_RMID, NULL); exit(0); default: break; }}}
int main(int argc, chr **argv) { key_t key; int msgid; key = ftok("/usr/mash", 's'); msgid = msgget(key, 0666) for(;;) { msgrcv(msgid, (struct msgbuf*) (&Message), 256, 1, 0); printf("%s",Message.Data); if (Message.Data[0]=='q' || Message.Data[0]=='Q') break; }exit();} #include struct { long mtype; char Data[256]; } Message; Процесс-приемник А
Пример. Очередь сообщений. Модель «клиент-сервер».
Server int main(int argc, chr **argv) { struct { long mestype; char mes [100]; } messageto; struct { long mestype; long mes; } messagefrom; key_t key; int mesid;... #include
Server … key = ftok("example", 'r'); mesid = msgget (key, 0666 | IPC_CREAT | IPC_EXCL ); while(1) { msgrcv(mesid, &messagefrom, sizeof(messagefrom)- sizeof(long), 1, 0) messageto.mestype = messagefrom.mes; strcpy( messageto.mes, "Message for client"); msgsnd (mesid, &messageto, sizeof(messageto)- sizeof(long),0); }
Client int main(int argc, chr **argv) { struct { long mestype; long mes; } messageto; struct { long mestype; char mes[100]; } messagefrom; key_t key; int mesid;... #include
Client... long pid = getpid(); key = ftok("example", 'r'); mesid = msgget (key, 0666); messageto.mestype = 1; messageto.mes = pid; msgsnd (mesid, &messageto, sizeof(messageto)-sizeof(long),0); msgrcv(mesid,&messagefrom, sizeof(messagefrom)-sizeof(long),pid,0); printf("%s",messagefrom.mes); return 0; }
IPC: разделяемая память.
#include int shmget (key_t key, int size, int shmflg) Создание общей памяти key – ключ для доступа к разделяемой памяти size – размер области памяти shmflg – флаги управляющие поведением вызова В случае успешного завершения вызов возвращает положительное число – дескриптор области памяти, в случае неудачи - -1.
#include char *shmat(int shmid, char *shmaddr, int shmflg) Доступ к разделяемой памяти shmid – дескриптор области памяти shmaddr – виртуальный адрес в адресном пространстве, начиная с которого необходимо подсоединить разделяемую память (чаще всего =0, то есть выбор предоставляется системе) shmflg – флаги, например, SHM_RDONLY подсоединяемая область будет использоваться только для чтения. Возвращает адрес, начиная с которого будет отображаться присоединяемая разделяемая память. При неудаче - -1.
#include int shmdt(char *shmaddr) Открепление разделяемой памяти shmaddr -адрес прикрепленной к процессу памяти, который был получен при вызове shmat() В случае успешного выполнения функция возвращает 0, в случае неудачи -1
#include int shmctl(int shmid, int cmd, struct shmid_ds *buf) Управление разделяемой памятью shmid – дескриптор области памяти cmd – IPC_STAT – скопировать структуру, описывающую управляющие параметры области памяти IPC_SET – заменить структуру, описывающую управляющие параметры области памяти, на структуру, находящуюся по адресу, указанному в параметре buf. IPC_RMID удалить SHM_LOCK, SHM_UNLOCK – блокировать или разблокировать область памяти. buf – структура, описывающая управляющие параметры области памяти.
int main(int argc, chr **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); exit(); } Пример. Работа с общей памятью в рамках одного процесса.
IPC: массив семафоров.
#include int semget (key_t key, int nsems, int semflag) Создание/доступ к семафору key – ключ nsems – количество семафоров semflag – флаги, определяющие права доступа и те операции, которые должны выполняться (открытие семафора, проверка, и т.д.). Возвращает целочисленный идентификатор созданного разделяемого ресурса, либо -1, если ресурс не удалось создать.
#include int semop (int semid, struct sembuf *semop, size_t nops) Операции над семафором semid – идентификатор ресурса semop – указатель на структуру, определяющую операции, которые нужно призвести над семафором nops– количество указателей на эту структуру, которые передаются функцией semop()
Операции над семафором struct sembuf { short sem_num; /*номер семафора в векторе*/ short sem_op; /*производимая операция*/ short sem_flg; /*флаги операции*/ } Значение семафора с номером num равно val. Если semop 0 то если val+semop < 0 то пока !(val+semop 0) [процесс стоит] val=val+semop Если semop = 0 то если val 0 то пока (val 0) [процесс стоит] [возврат из вызова]
#include int semctl (int semid, int num, int cmd, union semun arg) Управление массивом семафоров semid – дескриптор массива семафоров num – индекс семафора в массиве cmd – операция IPC_SET заменить управляющие наборы семафоров на те, которые указаны в arg.buf IPC_RMID удалить массив семафоров и др. arg – управляющие параметры Возвращает значение, соответствующее выполнявшейся операции (по умолчанию 0), в случае неудачи – -1
#include int semctl (int semid, int num, int cmd, union semun arg) Управление массивом семафоров union semun { int val; /* значение одного семафора *. struct semid_ds *buf; /* параметры массива семафоров в целом (количество, права доступа, статистика доступа)*/ ushort *array;/* массив значений семафоров */ }
Пример. Использование разделяемой памяти и семафоров.
1-ый процесс int 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 | IPC_EXCL); shmid = shmget(key, NMAX, 0666 | IPC_CREAT | IPC_EXCL); shmaddr = shmat(shmid, NULL, 0); … #include #define NMAX256
… semctl(semid, 0, SETVAL, (int) 0); sops.sem_num = 0; sops.sem_flg = 0; do { printf(Введите строку:); if (fgets(str, NMAX, stdin) == NULL) strcpy(str, Q); strcpy(shmaddr, str); sops.sem_op = 3; semop(semid, &sops, 1); sops.sem_op = 0; semop(semid, &sops, 1); } while (str[0] != Q); … shmdt(shmaddr); shmctl(shmid, IPC_RMID, NULL); semctl(semid, 0, IPC_RMID, (int) 0); return 0;} 1-ый процесс
2-ой процесс int 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); shmid = shmget(key, NMAX, 0666); shmaddr = shmat(shmid, NULL, 0); sops.sem_num = 0; … #include #define NMAX256
… sops.sem_flg = 0; do { printf(Waiting… \n); sops.sem_op = -2; semop(semid, &sops, 1); strcpy(str, shmaddr); if (str[0] == Q) shmdt(shmaddr); sops.sem_op = -1; semop(semid, &sops, 1); printf(Read from shared memory: %s\n, str); } while (str[0] != Q); return 0; } 2-ой процесс