
- •Сигналы:
- •Группы и сеансы
- •Управление сигналами
- •Отправление сигнала
- •Взаимодействие между процессами
- •Int pipe(int *fieldes);
- •Int mknod(char *pathname, int mode, int dev);
- •Сообщения
- •Int msgget(key_t key, int msgflag);
- •Int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
- •Int msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
- •Int semget(key_t key, int nsems, int semflag);
- •Int semop(int semid,
- •0, 1, 0}; /* Затем увеличить значение
- •0,1,0 /*Увеличить значение семафора на 1*/
- •Int shmget(key_t key, int size, int shmflag);
- •Int *shmat( int shmid, char *shmaddr, int shmflag);
- •Int shmdt(char *shmaddr);
- •Int segment;
- •Int shmid, semid;
Int pipe(int *fieldes);
который возвращает два файловых дескриптора
— fildes [0] для записи в канал и
— fildes[1] для чтения из канала.
Теперь, если один процесс записывает данные в fildes[0], другой сможет получить эти данные из fildes[1] .
Вопрос только в том, как другой процесс сможет получить сам файловый дескриптор fildes[ 1 ]?
Дочерний процесс наследует и разделяет все назначенные файловые дескрипторы родительского. То есть доступ к дескрипторам fildes канала может получить сам процесс, вызвавший pipe(), и его дочерние процессы.
В этом заключается серьезный недостаток каналов, поскольку они могут быть использованы для передачи данных только между родственными процессами. Каналы не могут использоваться в качестве средства межпроцессного взаимодействия между независимыми процессами.
в приведенном примере процессы cat() и wc() создаются процессом shell и являются родственными.
Рис. 3.17. Создание канала между задачами саt(1) и wc(1)
FIFO
Firt In First Out (первый вошел — первый вышел).
FIFO очень похожи на каналы, поскольку являются однонаправленным средством передачи данных, причем чтение данных происходит в порядке их записи.
в отличие от программных каналов, FIFO имеют имена, которые позволяют независимым процессам получить к этим объектам доступ.
Поэтому иногда FIFO также называют именованными каналами.
FIFO являются средством UNIX System V и не используются в BSD. Впервые FIFO были представлены в System III, однако они до сих пор не документированы и поэтому мало используются.
FIFO является отдельным типом файла в файловой системе UNIX (ls -l покажет символ р в первой позиции
Для создания FIFO используется системный вызов mknod():
Int mknod(char *pathname, int mode, int dev);
где pathname — имя файла в файловой системе (имя FIFO),
mode — флаги владения, прав доступа и т. д.,
dev - при создании FIFO игнорируется.
FIFO м.б. создан и из командной строки shell:
$ mknod name p
После создания FIFO может быть открыт на запись и чтение, причем запись и чтение могут происходить в разных независимых процессах.
Правила работы канала FIFO :
1. При чтении меньшего числа байтов, чем находится в канале или FIFO, возвращается требуемое числобайтов, остаток сохраняется для последующих чтений.
2. При чтении большего числа байтов, чем находится в канале или FIFO, возвращается доступное число байтов. Процесс, читающий из канала, должен соответствующим образом обработать ситуацию, когда прочитано меньше, чем заказано.
3. Если канал пуст и ни один процесс не открыл его на запись, при чтении из канала будет получено 0 байтов. Если один или более процессов открыли канал для записи, вызов read() будет заблокирован до появления данных .
4. Запись числа байтов, меньшего емкости канала или FIFO, гарантированно атомарно. Это означает, что в случае, когда несколько процессов одновременно записывают в канал, порции данных от этих процессов не перемешиваются.
5. При записи большего числа байтов, чем это позволяет канал или FIFO, вызов write() блокируется до освобождения требуемого места, При этом атомарность операции не гарантируется. Если процесс пытается записать данные в канал, не открытый ни одним процессом на чтение, процессу генерируется сигнал SIGPIPE, а вызов write() возвращает 0 с установкой ошибки (errno=EPIPE) (если процесс не установил обработки сигнала SIGPIPE, производится обработка по умолчанию — процесс завершается).
пример приложения клиент-сервер, использующего FIFO для обмена данными. Следуя традиции, клиент посылает серверу сообщение "Здравствуй, Мир!", а сервер выводит это сообщение на терминал.
Сервер:
#include <sys/types.h>
#include <sys/stat.h>
#define FIFO “fifo.1”
#define MAXBUFF 80
main()
{
int readfd, n;
char buff[MAXBUFF]; /*буфер для чтения данных из FIFO*/
/*Создадим специальный файл FIFO с открытыми для всех правами доступа на чтение и записаь*/
if(mknod(FIFO, S_FIFO | 0666, 0)<0
{
printf(“Невозможно создать FIFO\n”); exit(1); }
/*Получим доступ к FIFO*/
if ((readfd = open(FIFO, O_RDONLY))<0)
{
printf(“Невозможно открыть FIFO\n”);
exit(1); }
/*Прочитаем сообщение (“здравствуй, мир”) и выведем его на экран*/
while
((n = read(readfd, buff, MAXBUFF)) > 0)
if(write(1, buff, n) != n)
{
printf(“Ошибка вывода\n”); exit(1); }
/*Закроем FIFO, удаление FIFO – дело клиента*/
close(readfd);
exit(0);
}
Клиент:
#include <sys/types.h>
#include <sys/stat.h>
/*Соглашение об имени FIFO*/
#define FIFO “fifo.1”
main()
{
int writefd, n;
/*Получим доступ к FIFO*/
if ((writefd = open(FIFO, WRONLY)) < 0)
{
printf(“Невозможно открыть
FIFO\n”); exit(1); }
/*Передадим сообщение серверу FIFO*/
if(
write(writefd,”Здравствуй, Мир!\n”, 18) != 18)
{
printf(“Ошибка записи\n”); exit(1);}
/* Закроем FIFO */
close(writefd);
/* Удалим FIFO */
if(unlink(FIFO)<0 {
printf(“Невозможно удалить
FIFO\n”); exit(1); }
exit(0);
}
Идентификаторы и имена в IPC
Отсутствие имен у каналов делает их недоступными для независимых процессов.
Этот недостаток устранен у FIFO, которые имеют имена.
Другие средства межпроцессного взаимодействия, являющиеся более сложными, требуют дополнительных соглашений по именам и идентификаторам.
Множество возможных имен объектов конкретного типа межпроцессного взаимодействия называется пространством имен (name space).
Имена являются важным компонентом системы межпроцессного взаимодействия для всех объектов, кроме каналов, поскольку по зволяют различным процессам получить доступ к общему объекту.
именем FIFO является имя файла именованного канала. Используя условленное имя созданного FIFO два процесса могут обращаться к этому объекту для обмена данными.
Для таких объектов IРС, как очереди сообщений, семафоры и разделяемая память, процесс назначения имени является более сложным, чем просто указание имени файла.
Имя для этих объектов называется ключом (key) и генерируется функцией ftok()
из двух компонентов — имени файла и идентификатора проекта:
#include<sys/types.h>
#include<sys/ipc.h>
key_t ftok(char *filename, char proj);
где filename - имя некоторого файла, известное взаимодействующим процессам. Например, это может быть имя программы-сервера. Важно, чтобы этот файл существовал на момент создания ключа.
нежелательно использовать имя файла, который создается и удаляется в процессе работы распределенного приложения, поскольку при генерации ключа используется номер inode файла.
Вновь созданный файл может иметь другой inode и впоследствии процесс, желающий иметь доступ к объекту, получит неверный ключ.
Пространство имен позволяет создавать и совместно использовать IРС неродственным процессам. Однако для ссылок на уже созданные объекты используются идентификаторы, точно так же, как файловый дескриптор используется для работы с файлом, открытым по имени.
Каждое из перечисленных 1РС имеет свой уникальный дескриптор (идентификатор), используемый ОС (ядром) для работы с объектом. Уникальность дескриптора обеспечивается уникальностью дескриптора для каждого из типов объектов (очереди сообщений, семафоры и разделяемая память), т. е. какая-либо очередь сообщений может иметь тот же численный идентификатор, что и разделяемая область памяти (хотя любые две очереди сообщений должны иметь различные идентификаторы).
Таблица 3.5. Идентификация объектов 1РС
-
Объект IРС
Пространс
тво имен
Дескриптор
Канал
Файловый
дескриптор
FIFO
Имя файла
Файловый
дескриптор
Очередь
сообщений
Ключ
Идентификатор
Семафор
Ключ
Идентификатор
Разделяемая
память
Ключ
Идентификатор
Работа с объектами IPC System V во многом сходна.
Для создания или получения доступа к объекту используются соответствующие системные вызовы get:
mssget() для очереди сообщений,
semget() для семафора и
shmget() для разделяемой памяти.
Все эти вызовы возвращают дескриптор объекта в случае успеха и -1 в случае неудачи.
Функции get позволяют процессу получить ссылку на объект, которой по существу является возвращаемый дескриптор, но не позволяют производить конкретные операции над
Все функции get в качестве аргументов используют ключ key и флажки создания объекта ipcflag.
Остальные аргументы зависят от конкретного типа объекта.
Переменная ipcflag определяет права доступа к объекту PERM, а также указывает, создается ли новый объект или требуется доступ к существующему.
Последнее определяется комбинацией (или отсутствием) флажков IPC_CREAT и IPC_EXCL.
Права доступа к объекту указываются набором флажков доступа:
Комбинацией флажков можно добиться различных результатов:
Работа с объектами IPC System V во многом похожа на работу с файлами в UNIX.
Одним из различий является то, что файловые дескрипторы имеют значимость в контексте процесса, в то время как значимость дескрипторов объектов IPC распространяется на всю систему.
процессы, использующие одни объекты IPC, получат одинаковые дескрипторы этого объекта.
Для каждого из объектов IPC ядро поддерживает соответствующую структуру данных, отличную для каждого типа объекта IPC (очереди сообщений, семафора или разделяемой памяти).
Общей у этих данных является структура ipc_perm, описывающая права доступа к объекту, подобно тому, как это делается для файлов.
Основные поля структуры ipc_perm:
uid Идентификатор владельца-пользователя объекта
gid Идентификатор владельца-группы объекта
cuid UID создателя объекта (эффективные идентификаторы)
cgid GID создателя объекта
mode Права доступа на чтение и запись для всех классов доступа (9 битов)
key Ключ объекта
Права доступа (как и для файлов) определяют возможные операции, которые может выполнять над объектом конкретный процесс (получение доступа к существующему объекту, чтение, запись и удаление).
Система не удаляет созданные объекты IPC даже тогда, когда ни один процесс не пользуется ими.
Удаление созданных объектов является обязанностью процессов, которым для этого предоставляются соответствующие функции управления msgctl(), semctl(), shmctl().
С помощью этих функций процесс может получить и установить ряд полей внутри структур, поддерживаемых системой для объектов IРС, а также удалит созданные объекты.
Как и во многих других случаях использования объектов IРС процессы предварительно должны "договориться", какой процесс и когда удалит объект. Чаще всего, таким процессом является сервер.
.