Добавил:
Кафедра ВТ Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

lab8

.docx
Скачиваний:
19
Добавлен:
02.01.2023
Размер:
62.58 Кб
Скачать

МИНОБРНАУКИ РОССИИ

Санкт-Петербургский государственный

электротехнический университет

«ЛЭТИ» им. В.И. Ульянова (Ленина)

Кафедра вычислительной техники

Отчет по лабораторной работе №8

по дисциплине «Организация процессов и программирование в среде Linux»

Студент гр.

Преподаватель

Разумовский Г.В.

Тема: Взаимодействие процессов на основе сообщений

Цель работы: знакомство с механизмом обмена сообщениями и системными вызовами приема и передачи сообщений.

Задание:

1. Написать три программы, выполняющиеся параллельно и читающие один и тот же файл. Программа, которая хочет прочитать файл, должна передать другим программам запрос на разрешение операции и ожидать их ответа. Эти запросы программы передают через одну очередь сообщений. Ответы каждая программа должна принимать в свою локальную очередь. В запросе указываются: номер программы, которой посылается запрос, идентификатор очереди, куда надо передать ответ, и время посылки запроса. Начать выполнять операцию чтения файла программе разрешается только при условии получения ответов от двух других программ. Каждая программа перед отображением файла на экране должна вывести следующую информацию: номер программы и времена ответов, полученных от других программ.

Программа, которая получила запрос от другой программы, должна реагировать следующим образом:

  • если программа прочитала файл, то сразу передается ответ, который должен содержать номер отвечающей программы и время ответа;

  • если файл не читался, то ответ передается только при условии, что время посылки запроса в сообщении меньше, чем время запроса на чтение у данной программы. Запросы, на которые ответы не были переданы, должны быть запомнены и после чтения файла обслужены.

2. Откомпилировать 3 программы и запустить их несколько раз на разных терминалах в различной последовательности

Ход работы

Текст читаемого файла:

1. Is this the real life?

2. Is this just fantasy?

3. Caught in a landside,

4. No escape from reality

5. Open your eyes,

6. Look up to the skies and see,

7. I'm just a poor boy, I need no sympathy,

8. Because I'm easy come, easy go,

9. Little high, little low,

10. Any way the wind blows doesn't really matter to

11. Me, to me

Результат работы prog1.cpp

leatherman@leatherman-SHIT-SHIT:~/Desktop/8 lab$ g++ prog1.cpp -o prog1

leatherman@leatherman-SHIT-SHIT:~/Desktop/8 lab$ ./prog1 115

Очередь с ключом = 115 была создана. Ее id = 16.

Текущая временная метка: 1668535586

Отправка msg:

От: 1

К: 0

Время: 1668535586

ra: false

Отправка msg:

От: 2

К: 0

Время: 1668535586

ra: false

Сообщения запроса чтения для двух других программ были отправлены.

Получение msg...

Msg получено:

От: 0

К: 1

Время: 1668535588

ra: false

Прочитан запрос от: 1

Моя временная метка ниже, чем у него. Позвольте прочитать позже.

Получено: 1, обработано: 0

Получение msg...

Msg получено:

От: 0

К: 1

Время: 0

ra: true

Чтение разрешено из: 1

Получено: 2, обработано: 0

Получение msg...

Msg получено:

От: 0

К: 2

Время: 1668535590

ra: false

Прочитан запрос от: 2

Моя временная метка ниже, чем у него. Позвольте прочитать позже.

Получено: 3, обработано: 0

Получение msg...

Msg получено:

От: 0

К: 2

Время: 0

ra: true

Чтение разрешено из: 2

Время = 1668535590. Начать чтение файла:

"""

1. Is this the real life?

2. Is this just fantasy?

3. Caught in a landside,

4. No escape from reality

5. Open your eyes,

6. Look up to the skies and see,

7. I'm just a poor boy, I need no sympathy,

8. Because I'm easy come, easy go,

9. Little high, little low,

10. Any way the wind blows doesn't really matter to

11. Me, to me

"""

Прочитано!

Всем разрешено прочесть тоже.

Получено: 4, обработано: 2

Нажмите Enter, чтобы закрыть очередь сообщений с id = 16

============================== КОНЕЦ! ==============================

leatherman@leatherman-SHIT-SHIT:~/Desktop/8 lab$

Результат работы prog2.cpp

leatherman@leatherman-SHIT-SHIT:~/Desktop/8 lab$ g++ prog2.cpp -o prog2

leatherman@leatherman-SHIT-SHIT:~/Desktop/8 lab$ ./prog2 115

Было вложение в очередь с ключом = 115. Ее id = 16.

Текущая временная метка: 1668535588

Отправка msg:

От: 2

К: 1

Время: 1668535588

ra: false

Отправка msg:

От: 0

К: 1

Время: 1668535588

ra: false

Сообщения запроса чтения для двух других программ были отправлены.

Получение msg...

Msg получено:

От: 1

К: 0

Время: 1668535586

ra: false

Прочитан запрос от: 0

Моя временная метка больше, чем у него. Поэтому я разрешаю им читать тоже.

Получено: 1, обработано: 1

Получение msg...

Msg получено:

От: 1

К: 2

Время: 1668535590

ra: false

Прочитан запрос от: 2

Моя временная метка ниже, чем у него. Позвольте прочитать позже.

Получено: 2, обработано: 1

Получение msg...

Msg получено:

От: 1

К: 2

Время: 0

ra: true

Чтение разрешено из: 2

Получено: 3, обработано: 1

Получение msg...

Msg получено:

От: 1

К: 0

Время: 0

ra: true

Чтение разрешено из: 0

Время = 1668535590. Начать чтение файла:

"""

1. Is this the real life?

2. Is this just fantasy?

3. Caught in a landside,

4. No escape from reality

5. Open your eyes,

6. Look up to the skies and see,

7. I'm just a poor boy, I need no sympathy,

8. Because I'm easy come, easy go,

9. Little high, little low,

10. Any way the wind blows doesn't really matter to

11. Me, to me

"""

Прочитано!

Всем разрешено прочесть тоже.

Получено: 4, обработано: 2

============================== КОНЕЦ! ==============================

leatherman@leatherman-SHIT-SHIT:~/Desktop/8 lab$

Результат работы prog3.cpp

leatherman@leatherman-SHIT-SHIT:~/Desktop/8 lab$ g++ prog3.cpp -o prog3

leatherman@leatherman-SHIT-SHIT:~/Desktop/8 lab$ ./prog3 115

Было вложение в очередь с ключом = 115. Ее id = 16.

Текущая временная метка: 1668535590

Отправка msg:

От: 0

К: 2

Время: 1668535590

ra: false

Отправка msg:

От: 1

К: 2

Время: 1668535590

ra: false

Сообщения запроса чтения для двух других программ были отправлены.

Получение msg...

Msg получено:

От: 2

К: 0

Время: 1668535586

ra: false

Прочитан запрос от: 0

Моя временная метка больше, чем у него. Поэтому я разрешаю им читать тоже.

Получено: 1, обработано: 1

Получение msg...

Msg получено:

От: 2

К: 1

Время: 1668535588

ra: false

Прочитан запрос от: 1

Моя временная метка больше, чем у него. Поэтому я разрешаю им читать тоже.

Получено: 2, обработано: 2

Получение msg...

Msg получено:

От: 2

К: 0

Время: 0

ra: true

Чтение разрешено из: 0

Получено: 3, обработано: 2

Получение msg...

Msg получено:

От: 2

К: 1

Время: 0

ra: true

Чтение разрешено из: 1

Время = 1668535590. Начать чтение файла:

"""

1. Is this the real life?

2. Is this just fantasy?

3. Caught in a landside,

4. No escape from reality

5. Open your eyes,

6. Look up to the skies and see,

7. I'm just a poor boy, I need no sympathy,

8. Because I'm easy come, easy go,

9. Little high, little low,

10. Any way the wind blows doesn't really matter to

11. Me, to me

"""

Прочитано!

Всем разрешено прочесть тоже.

Получено: 4, обработано: 2

============================== КОНЕЦ! ==============================

leatherman@leatherman-SHIT-SHIT:~/Desktop/8 lab$

Текст prog1.cpp

#include <unistd.h>

#include <fcntl.h>

#include <sys/msg.h>

#include <iostream>

#define PROG_NUM 0

#define FILENAME "./text.txt"

#define Q_MAIN_OWNER 0

using std::cout;

using std::endl;

struct msg

{

long whom; // тип сообщения

int who; //кому это сообщение (whom - от кого)

long long time_stamp;

bool ra; //false-request, true-answer (read-allowed)

};

//длина передаваемого сообщения (структуры msg)

const unsigned MSG_LEN = sizeof(long) + sizeof(int) + sizeof(long long) + sizeof(bool);

void print_msg(const msg &msg_to_print);

int create_connect(unsigned prog_num, int queue_key);

void send_requests_to_read(unsigned prog_num, int queue_id, long long cur_time);

void read_file(int fd);

void send_allow_msg_from_current(msg &cur_msg, int queue_id);

/*

> ./main {queue_key}

*/

int main(int argc, char* argv[])

{

srandom(time(NULL));

if(argc != 2)

{

cout << "Ошибка синтаксиса. Ожидалось: \"> ./main {queue_key}\"" << endl;

exit(EXIT_FAILURE);

}

const unsigned prog_num = PROG_NUM;

const int queue_key = atoi(argv[1]);

if(queue_key <= 0)

{

cout << "{queue_key} должен быть не меньше 0. " << endl;

exit(EXIT_FAILURE);

}

int fd = open(FILENAME, O_RDONLY, S_IRUSR);

if(fd < 0)

{

perror("Не удалось открыть файл");

exit(EXIT_FAILURE);

}

//создает очередь сообщений, и все остальные программы коннектятся к ней

const int msqid = create_connect(prog_num, queue_key);

long long send_req_time = time(NULL);

cout << "Текущая временная метка: " << send_req_time << endl;

send_requests_to_read(prog_num, msqid, send_req_time);

cout << "Сообщения запроса чтения для двух других программ были отправлены.\n";

int queue_local = msgget(IPC_PRIVATE, 0666 | IPC_CREAT); //идентификатор очереди

//Ответы каждая программа должна принимать в свою локальную очередь.

int serviced = 0; //кол-во ответов запросов на чтение

int recieved_local = 0; // кол-во сообщений в локальной очереди

int recieved_all = 0; //всего полученных сообщений

int allowed = 0; //кол-во разрешений

//пока всем не ответил

while(serviced != 2 || recieved_all != 4)

{

cout << "Получение msg...\n";

msg rec_msg;

//прием сообщения (в rec_msg)

if(msgrcv(msqid, &rec_msg, MSG_LEN, prog_num+1, 0) != MSG_LEN) //прием здесь!!!

{

perror("msgrcv");

exit(EXIT_FAILURE);

}

++recieved_all;

cout << "Msg получено: \n";

print_msg(rec_msg);

if(rec_msg.ra == true)

{

//Одна из программ разрешила читать, помечаем это

cout << "Чтение разрешено из: " << (rec_msg.who-1) << endl;

++allowed;

//когда получено оба разрешения, читаем

if(allowed == 2)

{

cout << "Время = " << time(NULL) << ". Начать чтение файла: \n";

cout << "\"\"\"" << endl;

read_file(fd);

cout << endl << "\"\"\"" << endl;

cout << "Прочитано!\n";

while(recieved_local > 0)

{

msg l_msg;

msgrcv(queue_local, &l_msg, MSG_LEN, 0, 0);

--recieved_local;

send_allow_msg_from_current(l_msg, msqid);

++serviced;

}

cout << "Всем разрешено прочесть тоже.\n";

}

}

else //запрос на чтение

{

cout << "Прочитан запрос от: " << (rec_msg.who-1) << endl;

if(allowed >= 2)

{

//если файл прочитан, то другим читать можно

cout << "Я уже прочитал файл, поэтому я разрешаю им читать тоже.\n";

send_allow_msg_from_current(rec_msg, msqid);

++serviced;

}

else //если файл не прочитан, то

{

// Если программа послала запрос раньше нас, то ей даём разрешение

if(send_req_time < rec_msg.time_stamp)

{

cout << "Моя временная метка ниже, чем у него. Позвольте прочитать позже.\n";

msgsnd(queue_local, &rec_msg, MSG_LEN, 0); //вот здесь!

++recieved_local;

}

else //иначе откладываем запрос в долгий ящик

{

cout << "Моя временная метка больше, чем у него. Поэтому я разрешаю им читать тоже.\n";

send_allow_msg_from_current(rec_msg, msqid);

++serviced;

}

}

}

cout << "Получено: " << recieved_all << ", обработано: " << serviced << "\n\n\n";

}

close(fd);

if(prog_num == Q_MAIN_OWNER)

{

cout << "Нажмите Enter, чтобы закрыть очередь сообщений с id = " << msqid << endl;

getchar();

//удаление очереди главной программой

msgctl(msqid, IPC_RMID, NULL);

}

cout << "============================== КОНЕЦ! ==============================" << endl;

return 0;

}

//создает очередь сообщений, и все остальные коннектятся к ней

int create_connect(unsigned prog_num, int queue_key)

{

int idOfQueue;

if(prog_num == Q_MAIN_OWNER)

{

idOfQueue = msgget(queue_key, 0666 | IPC_CREAT | IPC_EXCL); //проверка наличия очереди с ключом

if(idOfQueue == -1) //если не получилось, вывести сообщение и выйти из программы

{

cout << "Не удается создать очередь сообщений. Очередь с ключом = " <<

queue_key << " уже существует, выберите другой\n";

exit(EXIT_FAILURE);

}

cout << "Очередь с ключом = " << queue_key << " была создана. Ее id = " << idOfQueue << ".\n";

}

else

{

do

{

idOfQueue = msgget(queue_key, IPC_EXCL);

if(idOfQueue == -1)

{

cout << "Очередь с ключом = " << queue_key << " еще не существует. Ожидание...\n";

}

}while(idOfQueue == -1);

idOfQueue = msgget(queue_key, IPC_CREAT);

cout << "Было вложение в очередь с ключом = " << queue_key << ". Ее id = " << idOfQueue << ".\n";

}

return idOfQueue;

}

//отправка первичного запроса

void send_requests_to_read(unsigned prog_num, int queue_id, long long cur_time)

{

msg _msg;

_msg.whom = (prog_num + 1) % 3 + 1;

_msg.who = prog_num+1;

_msg.time_stamp = cur_time;

_msg.ra = false;

cout << "Отправка msg:\n";

print_msg(_msg);

msgsnd(queue_id, &_msg, MSG_LEN, 0);

cout << endl;

//msgid – идентификатор очереди, в которую посылается сообщение

//msgp – адрес буфера, где располагается передаваемое сообщение

//msgsz – длина передаваемого сообщения

//msgflg –флаг, определяющий режим выполнения операции

_msg.whom = (prog_num + 2) % 3 + 1;

cout << "Отправка msg:\n";

print_msg(_msg);

msgsnd(queue_id, &_msg, MSG_LEN, 0);

cout << endl;

}

//отправка сообщения с разрешением на чтение

void send_allow_msg_from_current(msg &cur_msg, int queue_id)

{

unsigned buff;

buff = cur_msg.who;

cur_msg.who = cur_msg.whom;

cur_msg.whom = buff;

cur_msg.time_stamp = 0;

cur_msg.ra = true;

msgsnd(queue_id, &cur_msg, MSG_LEN, 0);

}

void print_msg(const msg &msg_to_print)

{

cout << "От: " << msg_to_print.whom-1 << endl;

cout << "К: " << msg_to_print.who-1 << endl;

cout << "Время: " << msg_to_print.time_stamp << endl;

cout << "ra: " << (msg_to_print.ra?"true":"false") << endl;

}

void read_file(int fd)

{

unsigned char c;

while(read(fd, &c, 1) != 0)

{

write(1, &c, 1);

}

}

Текст prog2.cpp

#include <unistd.h>

#include <fcntl.h>

#include <sys/msg.h>

#include <iostream>

#define PROG_NUM 1

#define FILENAME "./text.txt"

#define Q_MAIN_OWNER 0

using std::cout;

using std::endl;

struct msg

{

long whom; // тип сообщения

int who; //кому это сообщение (whom - от кого)

long long time_stamp;

bool ra; //false-request, true-answer (read-allowed)

};

//длина передаваемого сообщения (структуры msg)

const unsigned MSG_LEN = sizeof(long) + sizeof(int) + sizeof(long long) + sizeof(bool);

void print_msg(const msg &msg_to_print);

int create_connect(unsigned prog_num, int queue_key);

void send_requests_to_read(unsigned prog_num, int queue_id, long long cur_time);

void read_file(int fd);

void send_allow_msg_from_current(msg &cur_msg, int queue_id);

/*

> ./main {queue_key}

*/

int main(int argc, char* argv[])

{

srandom(time(NULL));

if(argc != 2)

{

cout << "Ошибка синтаксиса. Ожидалось: \"> ./main {queue_key}\"" << endl;

exit(EXIT_FAILURE);

}

const unsigned prog_num = PROG_NUM;

const int queue_key = atoi(argv[1]);

if(queue_key <= 0)

{

cout << "{queue_key} должен быть не меньше 0. " << endl;

exit(EXIT_FAILURE);

}

int fd = open(FILENAME, O_RDONLY, S_IRUSR);

if(fd < 0)

{

perror("Не удалось открыть файл");

exit(EXIT_FAILURE);

}

//создает очередь сообщений, и все остальные программы коннектятся к ней

const int msqid = create_connect(prog_num, queue_key);

long long send_req_time = time(NULL);

cout << "Текущая временная метка: " << send_req_time << endl;

send_requests_to_read(prog_num, msqid, send_req_time);

cout << "Сообщения запроса чтения для двух других программ были отправлены.\n";

int queue_local = msgget(IPC_PRIVATE, 0666 | IPC_CREAT); //идентификатор очереди

//Ответы каждая программа должна принимать в свою локальную очередь.

int serviced = 0; //кол-во ответов запросов на чтение

int recieved_local = 0; // кол-во сообщений в локальной очереди

int recieved_all = 0; //всего полученных сообщений

int allowed = 0; //кол-во разрешений

//пока всем не ответил

while(serviced != 2 || recieved_all != 4)

{

cout << "Получение msg...\n";

msg rec_msg;

//прием сообщения (в rec_msg)

if(msgrcv(msqid, &rec_msg, MSG_LEN, prog_num+1, 0) != MSG_LEN) //прием здесь!!!

{

perror("msgrcv");

exit(EXIT_FAILURE);

}

++recieved_all;

cout << "Msg получено: \n";

print_msg(rec_msg);

if(rec_msg.ra == true)

{

//Одна из программ разрешила читать, помечаем это

cout << "Чтение разрешено из: " << (rec_msg.who-1) << endl;

++allowed;

//когда получено оба разрешения, читаем

if(allowed == 2)

{

cout << "Время = " << time(NULL) << ". Начать чтение файла: \n";

cout << "\"\"\"" << endl;

read_file(fd);

cout << endl << "\"\"\"" << endl;

cout << "Прочитано!\n";

while(recieved_local > 0)

{

msg l_msg;

msgrcv(queue_local, &l_msg, MSG_LEN, 0, 0);

--recieved_local;

send_allow_msg_from_current(l_msg, msqid);

++serviced;

}

cout << "Всем разрешено прочесть тоже.\n";

}

}

else //запрос на чтение

{

cout << "Прочитан запрос от: " << (rec_msg.who-1) << endl;

if(allowed >= 2)

{

//если файл прочитан, то другим читать можно

cout << "Я уже прочитал файл, поэтому я разрешаю им читать тоже.\n";

send_allow_msg_from_current(rec_msg, msqid);

++serviced;

}

else //если файл не прочитан, то

{

// Если программа послала запрос раньше нас, то ей даём разрешение

if(send_req_time < rec_msg.time_stamp)

{

cout << "Моя временная метка ниже, чем у него. Позвольте прочитать позже.\n";

msgsnd(queue_local, &rec_msg, MSG_LEN, 0); //вот здесь!

++recieved_local;

}

else //иначе откладываем запрос в долгий ящик

{

cout << "Моя временная метка больше, чем у него. Поэтому я разрешаю им читать тоже.\n";

send_allow_msg_from_current(rec_msg, msqid);

++serviced;

}

}

}

cout << "Получено: " << recieved_all << ", обработано: " << serviced << "\n\n\n";

}

close(fd);

if(prog_num == Q_MAIN_OWNER)

{

cout << "Нажмите Enter, чтобы закрыть очередь сообщений с id = " << msqid << endl;

getchar();

//удаление очереди главной программой

msgctl(msqid, IPC_RMID, NULL);

}

cout << "============================== КОНЕЦ! ==============================" << endl;

return 0;

}

//создает очередь сообщений, и все остальные коннектятся к ней

int create_connect(unsigned prog_num, int queue_key)

{

int idOfQueue;

if(prog_num == Q_MAIN_OWNER)

{

idOfQueue = msgget(queue_key, 0666 | IPC_CREAT | IPC_EXCL); //проверка наличия очереди с ключом

if(idOfQueue == -1) //если не получилось, вывести сообщение и выйти из программы

{

cout << "Не удается создать очередь сообщений. Очередь с ключом = " <<

queue_key << " уже существует, выберите другой\n";

exit(EXIT_FAILURE);

}

cout << "Очередь с ключом = " << queue_key << " была создана. Ее id = " << idOfQueue << ".\n";

}

else

{

do

{

idOfQueue = msgget(queue_key, IPC_EXCL);

if(idOfQueue == -1)

{

cout << "Очередь с ключом = " << queue_key << " еще не существует. Ожидание...\n";

}

}while(idOfQueue == -1);

idOfQueue = msgget(queue_key, IPC_CREAT);

cout << "Было вложение в очередь с ключом = " << queue_key << ". Ее id = " << idOfQueue << ".\n";

}

return idOfQueue;

}

//отправка первичного запроса

void send_requests_to_read(unsigned prog_num, int queue_id, long long cur_time)

{

msg _msg;

_msg.whom = (prog_num + 1) % 3 + 1;

_msg.who = prog_num+1;

_msg.time_stamp = cur_time;

_msg.ra = false;

cout << "Отправка msg:\n";

print_msg(_msg);

msgsnd(queue_id, &_msg, MSG_LEN, 0);

cout << endl;

//msgid – идентификатор очереди, в которую посылается сообщение

//msgp – адрес буфера, где располагается передаваемое сообщение

//msgsz – длина передаваемого сообщения

//msgflg –флаг, определяющий режим выполнения операции

_msg.whom = (prog_num + 2) % 3 + 1;

cout << "Отправка msg:\n";

print_msg(_msg);

msgsnd(queue_id, &_msg, MSG_LEN, 0);

cout << endl;

}

//отправка сообщения с разрешением на чтение

void send_allow_msg_from_current(msg &cur_msg, int queue_id)

{

unsigned buff;

buff = cur_msg.who;

cur_msg.who = cur_msg.whom;

cur_msg.whom = buff;

cur_msg.time_stamp = 0;

cur_msg.ra = true;

msgsnd(queue_id, &cur_msg, MSG_LEN, 0);

}

void print_msg(const msg &msg_to_print)

{

cout << "От: " << msg_to_print.whom-1 << endl;

cout << "К: " << msg_to_print.who-1 << endl;

cout << "Время: " << msg_to_print.time_stamp << endl;

cout << "ra: " << (msg_to_print.ra?"true":"false") << endl;

}

void read_file(int fd)

{

unsigned char c;

while(read(fd, &c, 1) != 0)

{

write(1, &c, 1);

}

}

Текст prog3.cpp

#include <unistd.h>

#include <fcntl.h>

#include <sys/msg.h>

#include <iostream>

#define PROG_NUM 2

#define FILENAME "./text.txt"

#define Q_MAIN_OWNER 0

using std::cout;

using std::endl;

struct msg

{

long whom; // тип сообщения

int who; //кому это сообщение (whom - от кого)

long long time_stamp;

bool ra; //false-request, true-answer (read-allowed)

};

//длина передаваемого сообщения (структуры msg)

const unsigned MSG_LEN = sizeof(long) + sizeof(int) + sizeof(long long) + sizeof(bool);

void print_msg(const msg &msg_to_print);

int create_connect(unsigned prog_num, int queue_key);

void send_requests_to_read(unsigned prog_num, int queue_id, long long cur_time);

void read_file(int fd);

void send_allow_msg_from_current(msg &cur_msg, int queue_id);

/*

> ./main {queue_key}

*/

int main(int argc, char* argv[])

{

srandom(time(NULL));

if(argc != 2)

{

cout << "Ошибка синтаксиса. Ожидалось: \"> ./main {queue_key}\"" << endl;

exit(EXIT_FAILURE);

}

const unsigned prog_num = PROG_NUM;

const int queue_key = atoi(argv[1]);

if(queue_key <= 0)

{

cout << "{queue_key} должен быть не меньше 0. " << endl;

exit(EXIT_FAILURE);

}

int fd = open(FILENAME, O_RDONLY, S_IRUSR);

if(fd < 0)

{

perror("Не удалось открыть файл");

exit(EXIT_FAILURE);

}

//создает очередь сообщений, и все остальные программы коннектятся к ней

const int msqid = create_connect(prog_num, queue_key);

long long send_req_time = time(NULL);

cout << "Текущая временная метка: " << send_req_time << endl;

send_requests_to_read(prog_num, msqid, send_req_time);

cout << "Сообщения запроса чтения для двух других программ были отправлены.\n";

int queue_local = msgget(IPC_PRIVATE, 0666 | IPC_CREAT); //идентификатор очереди

//Ответы каждая программа должна принимать в свою локальную очередь.

int serviced = 0; //кол-во ответов запросов на чтение

int recieved_local = 0; // кол-во сообщений в локальной очереди

int recieved_all = 0; //всего полученных сообщений

int allowed = 0; //кол-во разрешений

//пока всем не ответил

while(serviced != 2 || recieved_all != 4)

{

cout << "Получение msg...\n";

msg rec_msg;

//прием сообщения (в rec_msg)

if(msgrcv(msqid, &rec_msg, MSG_LEN, prog_num+1, 0) != MSG_LEN) //прием здесь!!!

{

perror("msgrcv");

exit(EXIT_FAILURE);

}

++recieved_all;

cout << "Msg получено: \n";

print_msg(rec_msg);

if(rec_msg.ra == true)

{

//Одна из программ разрешила читать, помечаем это

cout << "Чтение разрешено из: " << (rec_msg.who-1) << endl;

++allowed;

//когда получено оба разрешения, читаем

if(allowed == 2)

{

cout << "Время = " << time(NULL) << ". Начать чтение файла: \n";

cout << "\"\"\"" << endl;

read_file(fd);

cout << endl << "\"\"\"" << endl;

cout << "Прочитано!\n";

while(recieved_local > 0)

{

msg l_msg;

msgrcv(queue_local, &l_msg, MSG_LEN, 0, 0);

--recieved_local;

send_allow_msg_from_current(l_msg, msqid);

++serviced;

}

cout << "Всем разрешено прочесть тоже.\n";

}

}

else //запрос на чтение

{

cout << "Прочитан запрос от: " << (rec_msg.who-1) << endl;

if(allowed >= 2)

{

//если файл прочитан, то другим читать можно

cout << "Я уже прочитал файл, поэтому я разрешаю им читать тоже.\n";

send_allow_msg_from_current(rec_msg, msqid);

++serviced;

}

else //если файл не прочитан, то

{

// Если программа послала запрос раньше нас, то ей даём разрешение

if(send_req_time < rec_msg.time_stamp)

{

cout << "Моя временная метка ниже, чем у него. Позвольте прочитать позже.\n";

msgsnd(queue_local, &rec_msg, MSG_LEN, 0); //вот здесь!

++recieved_local;

}

else //иначе откладываем запрос в долгий ящик

{

cout << "Моя временная метка больше, чем у него. Поэтому я разрешаю им читать тоже.\n";

send_allow_msg_from_current(rec_msg, msqid);

++serviced;

}

}

}

cout << "Получено: " << recieved_all << ", обработано: " << serviced << "\n\n\n";

}

close(fd);

if(prog_num == Q_MAIN_OWNER)

{

cout << "Нажмите Enter, чтобы закрыть очередь сообщений с id = " << msqid << endl;

getchar();

//удаление очереди главной программой

msgctl(msqid, IPC_RMID, NULL);

}

cout << "============================== КОНЕЦ! ==============================" << endl;

return 0;

}

//создает очередь сообщений, и все остальные коннектятся к ней

int create_connect(unsigned prog_num, int queue_key)

{

int idOfQueue;

if(prog_num == Q_MAIN_OWNER)

{

idOfQueue = msgget(queue_key, 0666 | IPC_CREAT | IPC_EXCL); //проверка наличия очереди с ключом

if(idOfQueue == -1) //если не получилось, вывести сообщение и выйти из программы

{

cout << "Не удается создать очередь сообщений. Очередь с ключом = " <<

queue_key << " уже существует, выберите другой\n";

exit(EXIT_FAILURE);

}

cout << "Очередь с ключом = " << queue_key << " была создана. Ее id = " << idOfQueue << ".\n";

}

else

{

do

{

idOfQueue = msgget(queue_key, IPC_EXCL);

if(idOfQueue == -1)

{

cout << "Очередь с ключом = " << queue_key << " еще не существует. Ожидание...\n";

}

}while(idOfQueue == -1);

idOfQueue = msgget(queue_key, IPC_CREAT);

cout << "Было вложение в очередь с ключом = " << queue_key << ". Ее id = " << idOfQueue << ".\n";

}

return idOfQueue;

}

//отправка первичного запроса

void send_requests_to_read(unsigned prog_num, int queue_id, long long cur_time)

{

msg _msg;

_msg.whom = (prog_num + 1) % 3 + 1;

_msg.who = prog_num+1;

_msg.time_stamp = cur_time;

_msg.ra = false;

cout << "Отправка msg:\n";

print_msg(_msg);

msgsnd(queue_id, &_msg, MSG_LEN, 0);

cout << endl;

//msgid – идентификатор очереди, в которую посылается сообщение

//msgp – адрес буфера, где располагается передаваемое сообщение

//msgsz – длина передаваемого сообщения

//msgflg –флаг, определяющий режим выполнения операции

_msg.whom = (prog_num + 2) % 3 + 1;

cout << "Отправка msg:\n";

print_msg(_msg);

msgsnd(queue_id, &_msg, MSG_LEN, 0);

cout << endl;

}

//отправка сообщения с разрешением на чтение

void send_allow_msg_from_current(msg &cur_msg, int queue_id)

{

unsigned buff;

buff = cur_msg.who;

cur_msg.who = cur_msg.whom;

cur_msg.whom = buff;

cur_msg.time_stamp = 0;

cur_msg.ra = true;

msgsnd(queue_id, &cur_msg, MSG_LEN, 0);

}

void print_msg(const msg &msg_to_print)

{

cout << "От: " << msg_to_print.whom-1 << endl;

cout << "К: " << msg_to_print.who-1 << endl;

cout << "Время: " << msg_to_print.time_stamp << endl;

cout << "ra: " << (msg_to_print.ra?"true":"false") << endl;

}

void read_file(int fd)

{

unsigned char c;

while(read(fd, &c, 1) != 0)

{

write(1, &c, 1);

}

}

Санкт-Петербург

2022

Соседние файлы в предмете Программирование в среде Linux