lab9
.docxМИНОБРНАУКИ РОССИИ
Санкт-Петербургский государственный
электротехнический университет
«ЛЭТИ» им. В.И. Ульянова (Ленина)
Кафедра вычислительной техники
Отчет по лабораторной работе №9
по дисциплине «Организация процессов и программирование в среде Linux»
Студент гр. |
|
Преподаватель |
Разумовский Г.В. |
Тема: ОБМЕН ДАННЫМИ ЧЕРЕЗ
РАЗДЕЛЯЕМУЮ ПАМЯТЬ
Цель работы: знакомство с организацией разделяемой памяти и системными функциями, обеспечивающими обмен данными между процессами.
Задание:
Написать 3 программы, которые запускаются в произвольном порядке и построчно записывают свои индивидуальные данные в один файл через определенный промежуток времени. Пока не закончит писать строку одна программа, другие две не должны обращаться к файлу. Частота записи данных в файл и количество записываемых строк определяются входными параметрами, задаваемыми при запуске каждой программы. При завершении работы одной из программ другие должны продолжить свою работу. Синхронизация работы программ должна осуществляться с помощью общих переменных, размещенных в разделяемой памяти.
Ход работы
Результат работы executable_0.cpp
Результат работы executable_1.cpp
Результат работы executable_2.cpp
Текст выходного файла
Written by program number 1
Written by program number 0
Written by program number 1
Written by program number 1
Written by program number 2
Written by program number 0
Written by program number 1
Written by program number 2
Written by program number 1
Written by program number 2
Written by program number 0
Written by program number 1
Written by program number 2
Written by program number 2
Written by program number 0
Written by program number 2
Written by program number 2
Written by program number 2
Written by program number 2
Written by program number 2
Текст executable_0.cpp
#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
#include <unistd.h>
#include <sys/shm.h>
using namespace std;
struct LamportStruct //структура, объект которого является общим (видимым для всех!)
{
bool choosing[3]; //массив со значениями, показывающий, какие процессы в данный момент заняты выбором
int number[3]; //массив со значениями приоритетов каждого процесса
//если у двух процессов одинаковый номер в очереди, то первее обслуживается тот, у кого меньший номер j (в цикле)
};
int main (int argc, char *argv[])
{
// ---------- Подготовка ----------
if (argc != 3)
{
cout << "Syntax error. Not enough arguments, must be 2: \"./executable_0 interval_time number_of_strings\"!\n";
exit(-1);
}
if (atoi(argv[1]) < 1)
{
cout << "Syntax error. Interval time to write file argument must be in range [1; +inf)!\n";
exit(-1);
}
if (atoi(argv[2]) < 1)
{
cout << "Syntax error. Number of strings to write file argument must be in range [1; +inf)!\n";
exit(-1);
}
int program_id = 0;
int interval_time = atoi(argv[1]);
int number_of_strings = atoi(argv[2]);
int key = 420; // номер ключа для разделяемой памяти
string filename = "shared_file.txt";
bool shared_mem_seg_owner; //кто является владельцем разделяемой памяти (текущий ли процесс?)
int shared_mem_seg_ptr; //указатель на разделяемую память
int local_token = -1; //номер текущего приоритета
string written_string = "Written by program number " + to_string(program_id) + "\n";
LamportStruct* shared_mem_seg; // необходимые для алгоритма данные
cout << "---------- PROGRAM NUMBER " << program_id << " ----------\n";
cout << "---------- OUTPUT FILENAME IS " << filename << " ----------\n";
cout << "---------- INTERVAL TIME/NUMBER OF STRINGS: " << interval_time << "/" << number_of_strings << " ----------\n";
cout << "---------- KEY IS " << to_string(key) << " ----------\n";
// ---------- Создание/открытие разделяемой памяти ----------
shared_mem_seg_ptr = shmget(key, sizeof(LamportStruct), 0666 | IPC_CREAT | IPC_EXCL);
if (shared_mem_seg_ptr != -1)
{
shared_mem_seg_owner = true;
cout << "SHARED MEMORY SEGMENT HAS BEEN CREATED\n\n";
}
else
{
shared_mem_seg_ptr = shmget(key, sizeof(LamportStruct), 0666 | IPC_CREAT);
if(shared_mem_seg_ptr == -1)
{
cout << "SHARED MEMORY SEGMENT HAS NOT BEEN OPENED\n\n";
exit(-1);
}
else
{
cout << "SHARED MEMORY SEGMENT HAS BEEN OPENED\n\n";
}
}
// ---------- Включение разделяемой памяти в адресное пространство процесса ----------
shared_mem_seg = (LamportStruct*)shmat(shared_mem_seg_ptr, 0, 0);
// ---------- Алгоритм пекарни Лампорта ----------
for (int i = 0; i < number_of_strings; i++) // Цикл с кол-вом вписываемых строк
{
// https://www.javatpoint.com/lamports-bakery-algorithm
// все переменные в массиве choosing иниц. в false, а в массиве number - в 0
sleep(interval_time);
shared_mem_seg->choosing[program_id] = true; // установка choosing[id] в true, чтобы другие программы знали, что данная программа занята выбором
local_token = -1;
//когда процесс хочет войти в критическую секцию, он выбирает больший номер приоритета, чем любой предыдущий номер
for (int k = 0; k < 3; k++)
{
if (shared_mem_seg->number[k] > local_token)
{
local_token = shared_mem_seg->number[k];
}
}
shared_mem_seg->number[program_id] = local_token + 1; // выбор наибольшего номера
shared_mem_seg->choosing[program_id] = false; // после завершения выбора конкретный процесс помечает значение в false
// ожидание других процессов
for(int j = 0; j < 3; j++) // процесс входит в цикл для оценки состояния других процессов
{
// процесс «i» ждет, пока какой-либо другой процесс «j» не выберет номер своего приоритета
while(shared_mem_seg->choosing[j] == true)
{}
//j от 0 до 3 - номера программ
//цикл - ожидание, пока все остальные процессы присвоят себе номер (приоритет)
//убеждаемся в том, что все выбрали номера
// Когда поток хочет войти в критическую секцию, он должен проверить, может ли он это сейчас сделать.
while((shared_mem_seg->number[j] != 0)//если у процесса существует какой-либо приоритет (по дефолту - 0)
&& ((shared_mem_seg->number[j] < shared_mem_seg->number[program_id]) //само сравнение приоритета (если наш приоритет больше какой-либо программы, мы ждем в очереди)
|| ((shared_mem_seg->number[j] == shared_mem_seg->number[program_id])//если у нас равные приоритеты (одни и те же номерки), то мы сравниваем не только по приоритету, но и по id этих процессов
&& (j < program_id))))
{}
//см. в Википедии со сравнениями приоритетов
//после ожидания заходим на новую итерацию цикла
//после неудовлетворения условия в цикле процесс входит в критическую секцию
}
cout << "OPEN OUTPUT FILE \"" << filename << "\" BY PROCESS №" << program_id << " \n";
ofstream local_file(filename, ios_base::app);
cout << "WRITE STRING №" << i << " BY PROCESS №" << program_id << " \n";
local_file << written_string;
cout << "CLOSE OUTPUT FILE \"" << filename << "\" BY PROCESS №" << program_id << " \n\n";
local_file.close();
// когда процесс завершает выполнение своей критической секции, он сбрасывает свой приоритет в 0
shared_mem_seg->number[program_id] = 0;
}
// ---------- Открепление разделяемой памяти от процесса ----------
shmdt((void*)shared_mem_seg);
if(shared_mem_seg_owner == true)
{
//Управление характеристиками разд. памяти (в данном случае, удаление)
shmctl(shared_mem_seg_ptr, IPC_RMID, NULL);
cout << "\nSHARED MEMORY SEGMENT HAS BEEN CLOSED\n";
}
return 0;
}
Текст executable_1.cpp
#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
#include <unistd.h>
#include <sys/shm.h>
using namespace std;
struct LamportStruct //структура, объект которого является общим (видимым для всех!)
{
bool choosing[3]; //массив со значениями, показывающий, какие процессы в данный момент заняты выбором
int number[3]; //массив со значениями приоритетов каждого процесса
//если у двух процессов одинаковый номер в очереди, то первее обслуживается тот, у кого меньший номер j (в цикле)
};
int main (int argc, char *argv[])
{
// ---------- Подготовка ----------
if (argc != 3)
{
cout << "Syntax error. Not enough arguments, must be 2: \"./executable_1 interval_time number_of_strings\"!\n";
exit(-1);
}
if (atoi(argv[1]) < 1)
{
cout << "Syntax error. Interval time to write file argument must be in range [1; +inf)!\n";
exit(-1);
}
if (atoi(argv[2]) < 1)
{
cout << "Syntax error. Number of strings to write file argument must be in range [1; +inf)!\n";
exit(-1);
}
int program_id = 1;
int interval_time = atoi(argv[1]);
int number_of_strings = atoi(argv[2]);
int key = 420; // номер ключа для разделяемой памяти
string filename = "shared_file.txt";
bool shared_mem_seg_owner; //кто является владельцем разделяемой памяти (текущий ли процесс?)
int shared_mem_seg_ptr; //указатель на разделяемую память
int local_token = -1; //номер текущего приоритета
string written_string = "Written by program number " + to_string(program_id) + "\n";
LamportStruct* shared_mem_seg; // необходимые для алгоритма данные
cout << "---------- PROGRAM NUMBER " << program_id << " ----------\n";
cout << "---------- OUTPUT FILENAME IS " << filename << " ----------\n";
cout << "---------- INTERVAL TIME/NUMBER OF STRINGS: " << interval_time << "/" << number_of_strings << " ----------\n";
cout << "---------- KEY IS " << to_string(key) << " ----------\n";
// ---------- Создание/открытие разделяемой памяти ----------
shared_mem_seg_ptr = shmget(key, sizeof(LamportStruct), 0666 | IPC_CREAT | IPC_EXCL);
if (shared_mem_seg_ptr != -1)
{
shared_mem_seg_owner = true;
cout << "SHARED MEMORY SEGMENT HAS BEEN CREATED\n\n";
}
else
{
shared_mem_seg_ptr = shmget(key, sizeof(LamportStruct), 0666 | IPC_CREAT);
if(shared_mem_seg_ptr == -1)
{
cout << "SHARED MEMORY SEGMENT HAS NOT BEEN OPENED\n\n";
exit(-1);
}
else
{
cout << "SHARED MEMORY SEGMENT HAS BEEN OPENED\n\n";
}
}
// ---------- Включение разделяемой памяти в адресное пространство процесса ----------
shared_mem_seg = (LamportStruct*)shmat(shared_mem_seg_ptr, 0, 0);
// ---------- Алгоритм пекарни Лампорта ----------
for (int i = 0; i < number_of_strings; i++) // Цикл с кол-вом вписываемых строк
{
// https://www.javatpoint.com/lamports-bakery-algorithm
// все переменные в массиве choosing иниц. в false, а в массиве number - в 0
sleep(interval_time);
shared_mem_seg->choosing[program_id] = true; // установка choosing[id] в true, чтобы другие программы знали, что данная программа занята выбором
local_token = -1;
//когда процесс хочет войти в критическую секцию, он выбирает больший номер приоритета, чем любой предыдущий номер
for (int k = 0; k < 3; k++)
{
if (shared_mem_seg->number[k] > local_token)
{
local_token = shared_mem_seg->number[k];
}
}
shared_mem_seg->number[program_id] = local_token + 1; // выбор наибольшего номера
shared_mem_seg->choosing[program_id] = false; // после завершения выбора конкретный процесс помечает значение в false
// ожидание других процессов
for(int j = 0; j < 3; j++) // процесс входит в цикл для оценки состояния других процессов
{
// процесс «i» ждет, пока какой-либо другой процесс «j» не выберет номер своего приоритета
while(shared_mem_seg->choosing[j] == true)
{}
//j от 0 до 3 - номера программ
//цикл - ожидание, пока все остальные процессы присвоят себе номер (приоритет)
//убеждаемся в том, что все выбрали номера
// Когда поток хочет войти в критическую секцию, он должен проверить, может ли он это сейчас сделать.
while((shared_mem_seg->number[j] != 0)//если у процесса существует какой-либо приоритет (по дефолту - 0)
&& ((shared_mem_seg->number[j] < shared_mem_seg->number[program_id]) //само сравнение приоритета (если наш приоритет больше какой-либо программы, мы ждем в очереди)
|| ((shared_mem_seg->number[j] == shared_mem_seg->number[program_id])//если у нас равные приоритеты (одни и те же номерки), то мы сравниваем не только по приоритету, но и по id этих процессов
&& (j < program_id))))
{}
//см. в Википедии со сравнениями приоритетов
//после ожидания заходим на новую итерацию цикла
//после неудовлетворения условия в цикле процесс входит в критическую секцию
}
cout << "OPEN OUTPUT FILE \"" << filename << "\" BY PROCESS №" << program_id << " \n";
ofstream local_file(filename, ios_base::app);
cout << "WRITE STRING №" << i << " BY PROCESS №" << program_id << " \n";
local_file << written_string;
cout << "CLOSE OUTPUT FILE \"" << filename << "\" BY PROCESS №" << program_id << " \n\n";
local_file.close();
// когда процесс завершает выполнение своей критической секции, он сбрасывает свой приоритет в 0
shared_mem_seg->number[program_id] = 0;
}
// ---------- Открепление разделяемой памяти от процесса ----------
shmdt((void*)shared_mem_seg);
if(shared_mem_seg_owner == true)
{
//Управление характеристиками разд. памяти (в данном случае, удаление)
shmctl(shared_mem_seg_ptr, IPC_RMID, NULL);
cout << "\nSHARED MEMORY SEGMENT HAS BEEN CLOSED\n";
}
return 0;
}
Текст executable_2.cpp
#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
#include <unistd.h>
#include <sys/shm.h>
using namespace std;
struct LamportStruct //структура, объект которого является общим (видимым для всех!)
{
bool choosing[3]; //массив со значениями, показывающий, какие процессы в данный момент заняты выбором
int number[3]; //массив со значениями приоритетов каждого процесса
//если у двух процессов одинаковый номер в очереди, то первее обслуживается тот, у кого меньший номер j (в цикле)
};
int main (int argc, char *argv[])
{
// ---------- Подготовка ----------
if (argc != 3)
{
cout << "Syntax error. Not enough arguments, must be 2: \"./executable_0 interval_time number_of_strings\"!\n";
exit(-1);
}
if (atoi(argv[1]) < 1)
{
cout << "Syntax error. Interval time to write file argument must be in range [1; +inf)!\n";
exit(-1);
}
if (atoi(argv[2]) < 1)
{
cout << "Syntax error. Number of strings to write file argument must be in range [1; +inf)!\n";
exit(-1);
}
int program_id = 0;
int interval_time = atoi(argv[1]);
int number_of_strings = atoi(argv[2]);
int key = 420; // номер ключа для разделяемой памяти
string filename = "shared_file.txt";
bool shared_mem_seg_owner; //кто является владельцем разделяемой памяти (текущий ли процесс?)
int shared_mem_seg_ptr; //указатель на разделяемую память
int local_token = -1; //номер текущего приоритета
string written_string = "Written by program number " + to_string(program_id) + "\n";
LamportStruct* shared_mem_seg; // необходимые для алгоритма данные
cout << "---------- PROGRAM NUMBER " << program_id << " ----------\n";
cout << "---------- OUTPUT FILENAME IS " << filename << " ----------\n";
cout << "---------- INTERVAL TIME/NUMBER OF STRINGS: " << interval_time << "/" << number_of_strings << " ----------\n";
cout << "---------- KEY IS " << to_string(key) << " ----------\n";
// ---------- Создание/открытие разделяемой памяти ----------
shared_mem_seg_ptr = shmget(key, sizeof(LamportStruct), 0666 | IPC_CREAT | IPC_EXCL);
if (shared_mem_seg_ptr != -1)
{
shared_mem_seg_owner = true;
cout << "SHARED MEMORY SEGMENT HAS BEEN CREATED\n\n";
}
else
{
shared_mem_seg_ptr = shmget(key, sizeof(LamportStruct), 0666 | IPC_CREAT);
if(shared_mem_seg_ptr == -1)
{
cout << "SHARED MEMORY SEGMENT HAS NOT BEEN OPENED\n\n";
exit(-1);
}
else
{
cout << "SHARED MEMORY SEGMENT HAS BEEN OPENED\n\n";
}
}
// ---------- Включение разделяемой памяти в адресное пространство процесса ----------
shared_mem_seg = (LamportStruct*)shmat(shared_mem_seg_ptr, 0, 0);
// ---------- Алгоритм пекарни Лампорта ----------
for (int i = 0; i < number_of_strings; i++) // Цикл с кол-вом вписываемых строк
{
// https://www.javatpoint.com/lamports-bakery-algorithm
// все переменные в массиве choosing иниц. в false, а в массиве number - в 0
sleep(interval_time);
shared_mem_seg->choosing[program_id] = true; // установка choosing[id] в true, чтобы другие программы знали, что данная программа занята выбором
local_token = -1;
//когда процесс хочет войти в критическую секцию, он выбирает больший номер приоритета, чем любой предыдущий номер
for (int k = 0; k < 3; k++)
{
if (shared_mem_seg->number[k] > local_token)
{
local_token = shared_mem_seg->number[k];
}
}
shared_mem_seg->number[program_id] = local_token + 1; // выбор наибольшего номера
shared_mem_seg->choosing[program_id] = false; // после завершения выбора конкретный процесс помечает значение в false
// ожидание других процессов
for(int j = 0; j < 3; j++) // процесс входит в цикл для оценки состояния других процессов
{
// процесс «i» ждет, пока какой-либо другой процесс «j» не выберет номер своего приоритета
while(shared_mem_seg->choosing[j] == true)
{}
//j от 0 до 3 - номера программ
//цикл - ожидание, пока все остальные процессы присвоят себе номер (приоритет)
//убеждаемся в том, что все выбрали номера
// Когда поток хочет войти в критическую секцию, он должен проверить, может ли он это сейчас сделать.
while((shared_mem_seg->number[j] != 0)//если у процесса существует какой-либо приоритет (по дефолту - 0)
&& ((shared_mem_seg->number[j] < shared_mem_seg->number[program_id]) //само сравнение приоритета (если наш приоритет больше какой-либо программы, мы ждем в очереди)
|| ((shared_mem_seg->number[j] == shared_mem_seg->number[program_id])//если у нас равные приоритеты (одни и те же номерки), то мы сравниваем не только по приоритету, но и по id этих процессов
&& (j < program_id))))
{}
//см. в Википедии со сравнениями приоритетов
//после ожидания заходим на новую итерацию цикла
//после неудовлетворения условия в цикле процесс входит в критическую секцию
}
cout << "OPEN OUTPUT FILE \"" << filename << "\" BY PROCESS №" << program_id << " \n";
ofstream local_file(filename, ios_base::app);
cout << "WRITE STRING №" << i << " BY PROCESS №" << program_id << " \n";
local_file << written_string;
cout << "CLOSE OUTPUT FILE \"" << filename << "\" BY PROCESS №" << program_id << " \n\n";
local_file.close();
// когда процесс завершает выполнение своей критической секции, он сбрасывает свой приоритет в 0
shared_mem_seg->number[program_id] = 0;
}
// ---------- Открепление разделяемой памяти от процесса ----------
shmdt((void*)shared_mem_seg);
if(shared_mem_seg_owner == true)
{
//Управление характеристиками разд. памяти (в данном случае, удаление)
shmctl(shared_mem_seg_ptr, IPC_RMID, NULL);
cout << "\nSHARED MEMORY SEGMENT HAS BEEN CLOSED\n";
}
return 0;
}
Санкт-Петербург
2022