Наследники для класса Actor. Очереди сообщений.
Доступ к
разделяемому ресурсу можно регулировать с помощью системного устройства
=очередь соообщений=
Опишем заголовочный файл (
actor.h
) с описанием структуры сообщений и класса Actor для действий через очередь сообщений
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <stdlib.h>
#include <sys/msg.h>
#include <time.h>
#include <errno.h>
#include <string.h>
#include <iostream>
#include <cstdlib>
#include <fstream>
#define PERM 0666
using namespace std;
// Сама очередь сообщений ограничена по памяти (4064 бай)
// поэтому сообщения не должны занимать много места
// структура сообщений
struct Mess{
// тип сообщений. При указании типа не равным 0,
// читаются только сообщения этого типа
// Если тип = 0, то читаются все сообщения
long type;
// буфер для содержательной части сообщения
char buf[100];
// могут быть и другие поля
int pid;// pid процесса
// для передачи целых чисел
int number;
};
class Actor{
// Две переменные для сообщений:
// для чтения и записи
Mess mSend, mRead;
// ключ для создания очереди сообщений,
// одной для разных процессов
key_t key;
// тип сообщения для чтения
long typeToRead;
// тип сообщения для посылки
long typeToSend;
// дескриптор очереди сообщений
int mesid;
// другие переменные
int lng,n;
public:
// конструктор создает очередь сообщений
Actor();
// деструктор удалаяет очередь сообщений
~Actor();
// открывает доступ к ресурсу посылкой сообщения в очередь
void welcome(int);
// что-то выполняет за int времени
void act(int);
// подготовить информацию для посылки текста
void toSend(string);
// получить прочитанный текст
void write();
// подготовка к посылке числа
void toSendNumber(int);
// получить число
int toGetNumber();
int stop(int);
};
Рассмотрим реализацию некоторых функций
#include "actor.h"
// Конструктор создает очередь сообщений
Actor::Actor(){
// ftok() генерит ключ, который нужен для создания очереди сообщений
// для генерации ключа нужен символ и СУЩЕСТВУЮЩИЙ в системе файл
if ((key = ftok("actor",'A'))<0){
printf("Can't get key\n");
exit(1);
}
// Создание очереди сообщений с проверкой существования
if((mesid = msgget(key,PERM|IPC_CREAT|IPC_EXCL))<0){
// если очередь уже есть (процесс не первый пришел), просто открываем
if(errno == EEXIST){
if ((mesid = msgget(key,0))< 0){
// если не получилось, прерываем программу
printf("Can't create message's queue\n");
exit(1);
}
}else{
// если другая ошибка - прерываем программу
printf("Can't create message's queue\n");
exit(1);
}
}
// пока все типы - 0
typeToSend=typeToRead = 0;
// полю в сообщении для посылки присваиваем свой pid
mSend.pid = getpid();
};
// Деструкт---++ор удаляет очередь.
// После завершения программы очередь остается в системе.
// Если ее не удалить, последующие запуски будут приводить к ошикам
// в работе программ
Actor::~Actor(){
// msgctl - манипулятор для очереди сообщений
if( msgctl(mesid,IPC_RMID,0)<---++0){
printf("Can't delete queue\n");
// exit(1);
}
};
// Открываем доступ к ресурсу.
// посылаем сообщений в очередь
// Если процесс может прочитать сообщение,
// он его читает и продолжает дальше работать
// если не может, переходит в ожидание
void Actor::welcome(int p){
// указываем тип сообщения
mSend.type = p;
// отсылаем сообщение.
// Здесь следует напсать провеку (удалось ли отослать сообщение)
msgsnd(mesid,(void*)&mSend,sizeof(Mess),0);
};
// Подготовка текста к передаче
void Actor::toSend(string s){
strcpy(mSend.buf,s.c_str());
};
// напечатаь полученный текст.
void Actor::write(){
string s=mRead.buf;
cout<<s<<endl;
};
// Закрыть ресурс.
// Читаем сообщение из очереди. Если нет сообщений, ждем.
// Если сообщение было, читаем и количество сообщений в очереди
// уменьшается на одно
int Actor::stop(int p){
mRead.type = p;
n=msgrcv(mesid,&mRead, sizeof(Mess), mRead.type,0);
if(n<0){
exit(1);
}
// возвращаем pid отправителя
return mRead.pid;
};
// что-то желаем tm секунд
void Actor::act(int tm){
sleep(tm);
};
Рассмотрим две программы: сервер и клиент, которые по-очереди могут вводить строки
Сервер
|
Клиент
|
#include "actor.h"
// сервер начинает певым
// он читает сообщения типа 2, а
// отсылает тип 1
int main(){
Actor a;
string s;
int time;
while(1){
cin>>s;
a.toSend(s);
if(s == "*") break;
a.welcome(1);
a.stop(2);
a.write();
}
return 0;
}
|
#include "actor.h"
// Клиент начинает вторым.
// Он читает сообщения типа 1, а отсылает тиа 2
int main(){
Actor a;
int rang;
int set = 0;
string s;
int time;
while(1){
a.stop(1);
a.write();
cin>>s;
if(s == "*") break;
a.toSend(s);
a.welcome(2);
}
return 0;
}
| ---++
Если нам хочется расширить возможности класса
Actor
, создадим класс-наследник
CWriter
для реализации чата. При этом будем учитывать, что любой процесс может начинать работу как первым, так и вторым.
Заголовочный файл
cwriter.h
// подключение заголовочного файла
// для класса actor
#include "actor.h"
// класс CWriter - НАСЛЕДНИК класса Actor
class CWriter:public Actor{
// дополнительные атрибуты
int myPid; //pid этого процесса
int otherPid; // pid собеседника
string s; // строка для сообщений
// типы сообщений (для ЭТОГО класса)
long typeToSend,typeToRead;
public:
// Конструктор и деструктор будут---++ использоваться
// из класса Actor
// нам нужна только дополнительная функция,
// которая поможет определить очередность посылок
int IamHere();
};
Рализация:
#include "cwriter.h"
int CWriter::IamHere(){
// посылаем сообщение типа 1
welcome(1);
// устанавливаем свой pid
int pd = getpid();
// pid собеседника
int pdd;
// будем читать из очереди и писать в нее,
// пока не получим другой pid
while(1){
if((pdd=stop(1))!= pd) break;
welcome(1);
}
typeToSend =pdd ;
typeToRead = pd;
cout<<"Все пришли: я-"<<typeToRead << " он - "<<typeToSend <<"\n";
return pdd;
};
Предполагается что для двух собеседников запускается одна и та же программа:
#include "cwriter.h"
int main(){
CWriter a;
// получаем pid собеседника
int opid = a.IamHere();
int pid = getpid();
int rang;
int set = 0;
cout<<"opid="<<opid<<endl;
string s;
// вычисляем очередность
// у кого больше pid, тот ходит первым.
rang = opid - pid;
while(1){
if(rang > 0 && set == 0){
cout<<"я хожу вторвым. жду\n";
a.stop(pid);
a.write();
}else{
cout<<"посылаю\n";
}
set++;
cin>>s;
if(s == "*") break;
a.toSend(s);---++
a.welcome(opid);
a.stop(pid);
a.write();
}
return 0;
}
Задачи
Задача 1
Для класса
Actor дописать функции для передачи чисел типа
int .
Задача 2.
На остановке стоит очередь из пассажиров. Иногда к остановке подъезжает автобус вместимостью N пассажтиров.
Каждый пассажир садится в автобус определенное (для себя время).
Автобус ждет пока садятся пассажиры
tm секунд. Если никакой пассажир в это время не садится в автобус, автобус уезжает.
Автобус не должен закрывать двери пока садится пассажир. Пассажир не должен пытаться сесть в автобус, который уехал или еще не приехал. Два и более пассажира не могут садится в автобус одновременно.
Написать два класса-наследника классу
Actor :
Bus и
Passenger и промоделировать работу остановки, запуском несколькоих процессов-пасажиров и автобусов.
#include "actor.h"
#include <ctime>
class Bus:public Actor{
int passnd; // вместимость
float timeBoard; // всремя загрузки
clock_t begin; // начало загрузки
public:
// коструктор int - пассажиры
// float для времени
Bus(int, float);
// подъезд автобуса
void arrive();
// отправление
void go();
};
class Passenger:public Actor{
int timeBoard; // время на посадку
int mpid; // pid пассажира
public:
// клнструктор
Passenger(int);
// посадка
void toSit();
};
Задача 3
Описать класс
Catalog как наследник класса
SystemFile.
Для демонстрации работы написать программу, которая печатает только файлы, принадлежащие пользователю, запустившему программу.
--
TatyanaOvsyannikova2011 - 02 Nov 2016