
- •Сравнение характеристик разных ос.
- •Задание
- •Вопросы коллоквиума.
- •«Наследники» Создание дочерних процессов
- •Задание
- •Вопросы коллоквиума
- •«Трубы» Использование программных каналов
- •Задание
- •Вопросы коллоквиума
- •«На деревню дедушке» Использование очереди сообщений
- •Задание
- •Вопросы коллоквиума
- •«Вспомнить всё» Использование семафоров и разделяемой памяти
- •Задание
- •Вопросы коллоквиума
Задание
Согласно указаниям преподавателя выбрать себе схему. Кружки на схеме символизируют процессы, черточки между ними – трубы, стрелки – входные/выходные файлы. Один/несколько процессов читают строки из текстового файла и пересылают их по трубам другим процессам. Каждый из процессов добавляет к строке свою фразу и отсылает её дальше. Последний/последние процессы в цепочки записывают полученную строку в файл на диск. Часть процессов не должна быть родственниками.
Вопросы коллоквиума
Могут ли процессы – братья общаться между собой через именованные каналы.
Чем именованный канал отличается от простого файла.
Чем неименованный канал отличается от простого файла.
Можно ли сдвинуть указатель позиционирования записи в трубе.
Чем отличаются друг от друга вызовы pipe и mknod.
«На деревню дедушке» Использование очереди сообщений
Реализация очередей сообщений в UNIX аналогична реализации UNIX-файлов. В частности, в адресном пространстве ядра имеется таблица очередей сообщений, в которой отслеживаются все очереди сообщений, создаваемые в системе. В каждой записи таблицы сообщений можно найти следующие данные, относящиеся к одной из очередей:
Имя, представляющее собой целочисленный идентификационный ключ, присвоенный очереди процессом, который ее создал. Другие процессы могут, указывая этот ключ, "открывать" очередь и получать дескриптор для доступа к ней.
UID и GID создателя очереди. Процесс, эффективный UID которого совпадает с UID создателя очереди сообщений, имеет право удалять очередь и изменять параметры управления ею.
UID и GID назначенного владельца. Эти идентификаторы обычно совпадают с идентификаторами создателя очереди, но создатель может изменять эти идентификаторы для переназначения владельца очереди и принадлежности к группе.
Права доступа к очереди для чтения-записи по категориям "владелец", "группа" и "прочие". Процесс, имеющий право на чтение сообщений из очереди, может получать сообщения и запрашивать UID и GID назначенного владельца этой очереди. Процесс, имеющий право на запись в очередь, может передавать в нее сообщения.
Время и идентификатор процесса, который последним передал сообщение в очередь.
Время и идентификатор процесса, который последним прочитал сообщение из очереди.
Указатель на связный список сообщений, находящихся в очереди. В каждой записи списка хранится одно сообщение и присвоенный ему тип.
Когда процесс передает сообщение в очередь, ядро создает для него новую запись и помещает ее в конец связного списка записей, соответствующих сообщениям указанной очереди. В каждой такой записи указывается тип сообщения, число байтов данных, содержащихся в сообщении, и указатель на другую область данных ядра, где фактически находятся данные сообщения. Ядро копирует данные, содержащиеся в сообщении, из адресного пространства процесса-отправителя в эту область данных ядра, чтобы процесс-отправитель мог завершиться, а сообщение осталось доступным для чтения другими процессами.
Когда процесс выбирает сообщение из очереди, ядро копирует относящиеся к нему данные из записи сообщения в адресное пространство этого процесса, а затем удаляет запись. Процесс может выбрать сообщение из очереди следующими способами:
Выбрать самое старое сообщение, независимо от его типа.
Выбрать сообщение, идентификатор которого совпадает с идентификатором, указанным процессом. Если в очереди есть несколько сообщений заданного типа, из них выбирается самое старое.
Выбрать сообщение, числовое значение типа которого — наименьшее из меньших или равных значению типа, указанного процессом. Если этому критерию удовлетворяют несколько сообщений, из них выбирается самое старое.
Если процесс попытается прочитать сообщение из очереди, в которой ни одно сообщение не удовлетворяет критерию поиска, ядро по умолчанию переведет его в состояние ожидания (пока в очередь не поступит сообщение, которое этот процесс сможет прочитать). Если же процесс укажет в системном вызове приема сообщения неблокирующий флаг, то этот вызов не заблокирует процесс, а выдаст код неудачного завершения.
В заголовке <sys/ipc.h> объявляется тип данных struct ipc_perm, который используется для хранения UID создателя, UID владельца, идентификаторов их групп, имени (ключа) очереди и прав на чтение и запись для той или иной очереди сообщений.
Запись таблицы сообщений имеет тип данных struct msqid_ds, определяемый в заголовке <sys/message.h>. Ниже перечислены информационные поля этой структуры и данные, которые в них хранятся.
Поле |
Данные |
msg_perm |
Данные, хранящиеся в записи типа struct ipc_perm |
msg_first |
Указатель на первое (самое старое) сообщение в очереди |
msg_last |
Указатель на последнее (самое новое) сообщение в очереди |
msg_cbyte |
Общее число байтов во всех сообщениях, находящихся в очереди на данный момент |
msg_qnum |
Общее число сообщений, находящихся в очереди на данный момент |
msg_qbyte |
Максимальное число байтов во всех сообщениях, которые могут находиться в очереди. Обычно это MSGMNB, но создатель или назначенный владелец очереди может установить и более низкое значение |
msg_lspid |
Идентификатор процесса, который последним передал в очередь сообщение |
msg_lrpid |
Идентификатор процесса, который последним прочитал из очереди сообщение |
msg_stime |
Время, когда в очередь было передано самое последнее сообщение |
msg_rtime |
Время, когда из очереди было прочитано самое последнее сообщение |
msg_ctime |
Время последнего изменения управляющих параметров очереди сообщений (прав доступа, идентификатора владельца и идентификатора группы владельца) |
Структура struct msg, определенная в заголовке <sys/msg.h>,— это тип данных для записи сообщения. Ниже перечислены информационные поля этой структуры и данные, которые в них приводятся.
Поле |
Данные |
msg_type |
Целочисленный тип, присвоенный сообщению |
msg_ts |
Количество байтов в тексте сообщения |
msg_spot |
Указатель на текст сообщения, который хранится в другой области данных ядра |
msg_next |
Указатель на следующую запись сообщения или NULL, если это последняя запись в очереди сообщений |
Прототип функции msgget выглядит следующим образом:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/message.h>
int msgget (key_t key, int flag );
Эта функция открывает очередь сообщений, идентификатор которой совпадает со значением аргумента key, и возвращает положительный целочисленный дескриптор. Его можно использовать в других функциях сообщений для передачи и приема сообщений, а также для запроса и/или установки
управляющих параметров очереди.
Если значение аргумента key — положительное целое, эта функция пробует открыть очередь сообщений, идентификатор которой совпадает с данным значением. Если же значением key является макрос IPC_PRIVATE, вызов создает новую очередь сообщений, которая будет использоваться исключительно вызывающим процессом.
Если аргумент flag имеет нулевое значение и нет очереди сообщений, идентификатор которой совпадал бы с заданным значением key, то вызов прерывается; в противном случае возвращается дескриптор этой очереди. Если процессу необходимо создать новую очередь (когда нет ни одной очереди), то значение аргумента flag должно содержать макрос IPC_CREAT, а также права на чтение сообщений из новой очереди и запись в нее (для владельца, группы и прочих).
Если желательно иметь гарантию создания новой очереди сообщений, можно указать одновременно с флагом IPC_CREAT флаг IPC_EXCL, и этот вызов будет успешно выполнен только в том случае, если он создаст новую очередь с заданным значением key.
В случае неудачи такой вызов возвращает -1.
Прототип функции msgsnd выглядит следующим образом:
#include <sys/types.h>
#indude <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msgfd, const void*msgPtr, int len, int flag)
Эта функция передает сообщение (на которое указывает msgPtr) в очередь, обозначенную дескриптором msgfd.
Значение msgfd определяется возвращаемым значением функции msgget.
Фактическое значение аргумента msgPtr — указатель на объект, который содержит реальный текст и тип сообщения, подлежащего передаче. Для объявления объекта в этом случае можно использовать следующий тип данных:
struct msgbuf
{long mtype; // тип сообщения
char mtext[MSGMAX]; // буфер для текста сообщения
};
Значение аргумента len — это размер (в байтах) поля mtext объекта, на который указывает аргумент msgPtr.
Аргумент flag может иметь значение 0. Это означает, что при необходимости процесс можно блокировать до тех пор, пока данная функция не будет успешно выполнена. Если этот аргумент имеет значение IPC_NOWAIT, то при блокировании процесса выполнение функции прерывается.
В случае успешного выполнения возвращается 0, а в случае неудачи -1.
Прототип функции msgrcv выглядит так:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd (int msgfd, const void* msgPtr, int len, int mtype, int flag );
Эта функция принимает сообщение типа mtype из очереди сообщений, обозначенной дескриптором msgfd. Полученное сообщение хранится в объекте, на который указывает аргумент msgPtr. Значение аргумента len — это максимальный размер (в байтах) текста сообщения, которое может быть принято данным вызовом.
Значение msgfd берется из вызова функции msgget.
Фактическое значение аргумента msgPtr — указатель на объект, имеющий структуру данных, похожую на struct msgbuf.
Значение mtype — это тип сообщения, подлежащего приему. Ниже перечислены возможные значения данного аргумента и их смысл.
Значение mtype |
Смысл |
0 |
Принять из очереди самое старое сообщение любого типа |
Положительное целое |
Принять самое старое сообщение указанного типа |
Отрицательное целое |
Принять сообщение, тип которого меньше абсолютного значение mtype или равен ему. Если таких сообщении в очереди несколько, принять то, которое является самым старым и имеет наименьшее значение типа |
Аргумент flag может иметь значение 0. Это означает, что процесс можно блокировать, если ни одно сообщение в очереди не удовлетворяет критериям выбора, заданным аргументом mtype. Если в очереди есть сообщение, которое удовлетворяет этим критериям, но превышает величину len, то функция возвращает код неудачного завершения.
Если процесс указал в аргументе flag значение IPC_NOWAIT, то вызов будет неблокирующим. Кроме того, если в названном аргументе установлен флаг MSG_NOERROR, то сообщение, находящееся в очереди, можно читать (даже если его размер превышает len байтов). Функция возвращает вызывающему процессу первые len байтов текста сообщения, а остальные данные отбрасывает.
Функция msgrcv возвращает количество байтов, записанных в буфер mfext объекта, на который указывает аргумент msgPtr, или -1 (в случае неудачи).
Прототип функции msgctl имеет следующий вид:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl (int msgfd, int cmd struct msqid_ds* mbufPtr );
С помощью этой функции можно запрашивать управляющие параметры очереди сообщений, обозначенной аргументом msgfd, изменять информацию в управляющих параметрах очереди, удалять очередь из системы.
Значение аргумента msgfd берется из вызова функции msgget.
Ниже перечислены возможные значения аргумента cmd и их смысл.
Значение cmd |
Смысл |
IPC_STAT |
Копировать управляющие параметры очереди в объект, указанный аргументом mbufPtr |
IPC_SET |
Заменить управляющие параметры очереди параметрами, содержащимися в объекте, на который указывает аргумент mbufPtr. Чтобы выполнить эту операцию, вызывающий процесс должен иметь права либо привилегированного пользователя, либо создателя или назначенного владельца очереди. С помощью этого вызова можно устанавливать DID владельца очереди и идентификатор его группы, права доступа и (или) уменьшать лимит msg_qhyte очереди |
IPC_RMID |
Удалить очередь из системы. Чтобы выполнить эту операцию, вызывающий процесс должен иметь права либо привилегированного пользователя, либо создателя или назначенного владельца очереди |
В случае успешного выполнения возвращается 0, в случае неудачи -1.
В приведенном ниже примере исполнимый файл ./proba1 создаёт очередь сообщений и записывает туда два сообщения разных типов. ./proba2 читает из очереди сообщений, а ./proba3 удаляет очередь сообщений.
/*proba1.c*/
#include<iostream.h>
#include<stdio.h>
#include<sys/types.h>
#include<string.h>
#include<sys/stat.h>
#include<sys/msg.h>
#define MSGMAX 1024
struct mbuf
{
long mtype;
char mtext[MSGMAX];
}mobj={15,"Hello"},mobj16={16,"By"};
int main()
{
int fd,st,i;
fd = msgget(100,IPC_CREAT|0666);
if(fd==-1||msgsnd(fd,&mobj,strlen(mobj.mtext)+1,IPC_NOWAIT))
perror("message");
msgsnd(fd,&mobj16,strlen(mobj16.mtext)+1,IPC_NOWAIT);
return 0;
}
/*proba2.c*/
#include<iostream.h>
#include<stdio.h>
#include<string.h>
#include<sys/stat.h>
#include<sys/msg.h>
#define MSGMAX 1024
struct mbuf
{
long mtype;
char mtext[MSGMAX];
}mobj;
int main()
{
int i,fd;
fd = msgget(100,IPC_CREAT|0666);
if(fd==-1)
perror("message");
for(i=0;i<7;i++)
{
if (msgrcv(fd,&mobj,MSGMAX,-18,0)>0)
cout << mobj.mtext <<endl;
else perror("msgrcv не отработал");
}
return 0;
}
/*proba3.c*/
#include<iostream.h>
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/ipc.h>
#include<sys/msg.h>
int main()
{
struct msqid_ds mbuf;
int fd,st,i;
fd = msgget(100,0);
if(msgctl(fd,IPC_RMID,0))
perror("msgctl-IPC_RMID\n");
return 0;
}