#include ‹sys/types.h›
#include ‹sys/ipc.h›
#include ‹sys/msg.h›
#define MSGKEY 75
struct msgform {
long mtype;
char mtext[256];
} msg;
int msgid;
main() {
int i, pid, *pint;
extern cleanup();
for (i = 0; i ‹ 20; i++) signal(i, cleanup);
msgid = msgget(MSGKEY, 0777, IPC_CREAT);
for (;;) {
msgrcv(msgid, &msg, 256, 1, 0);
pint = (int *) msg.mtext;
pid = *pint;
printf("сервер: получил от процесса с pid %d\n", pid);
msg.mtype = pid;
*pint = getpid();
msgsnd(msgid, &msg, sizeof(int), 0);
}
}
cleanup() {
msgctl(msgid, IPC_RMID, 0);
exit();
}
Рисунок 11.8. Обслуживающий процесс (сервер)
Сообщения имеют форму "тип — текст", где текст представляет собой поток байтов. Указание типа дает процессам возможность выбирать сообщения только определенного рода, что в файловой системе не так легко сделать. Таким образом, процессы могут выбирать из очереди сообщения определенного типа в порядке их поступления, причем эта очередность гарантируется ядром. Несмотря на то, что обмен сообщениями может быть реализован на пользовательском уровне средствами файловой системы, представленный вашему вниманию механизм обеспечивает более эффективную организацию передачи данных между процессами.
С помощью системной функции msgctl процесс может запросить информацию о статусе дескриптора сообщения, установить этот статус или удалить дескриптор сообщения из системы. Синтаксис вызова функции:
msgctl(id, cmd, mstatbuf)
где id — дескриптор сообщения, cmd — тип команды, mstatbuf — адрес пользовательской структуры, в которой будут храниться управляющие параметры или результаты обработки запроса. Более подробно об аргументах функции пойдет речь в Приложении.
Вернемся к примеру, представленному на Рисунке 11.8. Обслуживающий процесс принимает сигналы и с помощью функции cleanup удаляет очередь сообщений из системы. Если же им не было поймано ни одного сигнала или был получен сигнал SIGKILL, очередь сообщений остается в системе, даже если на нее не ссылается ни один из процессов. Дальнейшие попытки исключительно создания новой очереди сообщений с данным ключом (идентификатором) не будут иметь успех до тех пор, пока старая очередь не будет удалена из системы.
Процессы могут взаимодействовать друг с другом непосредственно путем разделения (совместного использования) участков виртуального адресного пространства и обмена данными через разделяемую память. Системные функции для работы с разделяемой памятью имеют много сходного с системными функциями для работы с сообщениями. Функция shmget создает новую область разделяемой памяти или возвращает адрес уже существующей области, функция shmat логически присоединяет область к виртуальному адресному пространству процесса, функция shmdt отсоединяет ее, а функция shmctl имеет дело с различными параметрами, связанными с разделяемой памятью. Процессы ведут чтение и запись данных в области разделяемой памяти, используя для этого те же самые машинные команды, что и при работе с обычной памятью. После присоединения к виртуальному адресному пространству процесса область разделяемой памяти становится доступна так же, как любой участок виртуальной памяти; для доступа к находящимся в ней данным не нужны обращения к каким-то дополнительным системным функциям.
Синтаксис вызова системной функции shmget:
shmid = shmget(key, size, flag);
где size — объем области в байтах. Ядро использует key для ведения поиска в таблице разделяемой памяти: если подходящая запись обнаружена и если разрешение на доступ имеется, ядро возвращает вызывающему процессу указанный в записи дескриптор. Если запись не найдена и если пользователь установил флаг IPC_CREAT, указывающий на необходимость создания новой области, ядро проверяет нахождение размера области в установленных системой пределах и выделяет область по алгоритму allocreg (раздел 6.5.2). Ядро записывает установки прав доступа, размер области и указатель на соответствующую запись таблицы областей в таблицу разделяемой памяти (Рисунок 11.9) и устанавливает флаг, свидетельствующий о том, что с областью не связана отдельная память. Области выделяется память (таблицы страниц и т. п.) только тогда, когда процесс присоединяет область к своему адресному пространству. Ядро устанавливает также флаг, говорящий о том, что по завершении последнего связанного с областью процесса область не должна освобождаться. Таким образом, данные в разделяемой памяти остаются в сохранности, даже если она не принадлежит ни одному из процессов (как часть виртуального адресного пространства последнего).
Читать дальше