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

lab10

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

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

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

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

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

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

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

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

Студент гр.

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

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

Тема: СИНХРОНИЗАЦИЯ ПРОЦЕССОВ

С ПОМОЩЬЮ СЕМАФОРОВ

Цель работы: знакомство с организацией семафоров, системными

функциями, обеспечивающими управление семафорами, и их использованием для решения задач взаимоисключения и синхронизации.

Задание:

Написать две программы, экземпляры которых запускаются параллельно и с различной частотой обращаются к общему файлу. Каждый процесс из первой группы (Писатель) пополняет файл определенной строкой символов и выводит ее на экран вместе с именем программы. Процессы второй группы (Читатели) считывают весь файл и выводят его на экран. Писатели имеют приоритет перед Читателями. Пока один Писатель записывает строку в файл, другим Писателям и всем Читателям запрещено обращение к файлу. Читатели могут одновременно читать файл, если нет Писателей, готовых к записи в файл. Писатель заканчивает работу, после того как выполнит N-кратную запись строки в файл. Читатель заканчивает работу после прочтения текущего содержимого файла. Синхронизация процессов должна выполняться с помощью семафоров.

Ход работы

Результат работы двух писателей и двух читателей (начало)

Результат работы двух писателей и двух читателей (конец)

Текст выходного файла

Текст writer.cpp

// на всякий случай: ipcrm -s sem_id

#include <iostream>

#include <fstream>

#include <string>

#include <sys/ipc.h>

#include <sys/sem.h>

#include <unistd.h>

/*

Номер семаформа в множественном семафоре:

0-й -- для файла (для отслеживания писателей, которые хотят писать)

1-й -- количество писателей, которые хотят записать

2-й -- количество читателей, которые хотят прочитать

3-й -- общее количество работающих программ

*/

using namespace std;

int sem_key = 420; // ключ для создания/открытия семафора

int nProg = 4;

string file_name = "file.txt"; // имя файла, чтобы записывать/считывать

//{индекс простого семафора, код операции, флаг операции}

//semaphore_file_decrease

struct sembuf sem_file_dec = {0, -1, 0}; // уменьшаем семафор на 1, отвечающий за доступ 1-го писателя к файлу

struct sembuf sem_file_in = {0, 1, 0}; // увеличиваем семафор на 1, отвечающий за доступ 1-го писателя к файлу

struct sembuf sem_writer_com = {1, 0, 0}; // сравниваем активных писателей с 0 и ждём, пока они станут =0

//semaphore_writers_decrease

struct sembuf sem_writer_dec = {1, -1, 0}; // уменьшаем семафор на 1, отвечающий за активных писателей

struct sembuf sem_writer_in = {1, 1, 0}; // увеличиваем семафор на 1, отвечающий за активных писателей

//semaphore_readers_compare

struct sembuf sem_reader_com = {2, 0, 0}; // сравниваем активных читателей с 0 и ждём, пока они станут =0

struct sembuf sem_reader_dec = {2, -1, 0}; // уменьшаем семафор на 1, отвечающий за активных читателей

struct sembuf sem_reader_in = {2, 1, 0}; // увеличиваем семафор на 1, отвечающий за активных читателей

//semaphore_processes_decrease

struct sembuf sem_proc_dec = {3, -1, 0}; // уменьшаем семафор на 1, отвечающий за число активных программ

struct sembuf sem_proc_in = {3, 1, 0}; // увеличиваем семафор на 1, отвечающий за число активных программ

using namespace std;

int main (int argc, char* argv[]) // 1 -- количество строк, 2 -- время задержки

{

int sem_id; // ID семафора, возвращаемый при создании/открытии

ofstream file; // файл для записи

cout << "Процесс id=" << getpid() << "\n" << "Имя файла " << file_name << "\n" << "Ключ семафора " << sem_key << "\n";

// semget(ключ семафора, количество семафоров в наборе (4 штуки), флаги для создания семафора и с правом доступа у всех)

sem_id = semget(sem_key, nProg, IPC_CREAT | IPC_EXCL | 0666); // создаём семафор

if (sem_id != -1)

{

cout << "Семафор id=" << sem_id << " создан процессом id=" << getpid() << "\n";

// при создании семафора увеличиваем его на 1

// этот семафор нужен только для писателей; для отслеживания возможности записи в файл в данный момент

// при входе в цикл делаем -1, и тогда он будет = 0 (потому что он уже +1 ПРИ создании), поэтому остальные (писатели) не могут сделать -1 в цикле

// так как не стоит флаг IPC_NOWAIT, который сразу возвращает ошибку,

// и остальные программы вынуждены ждать, пока семафор будет =1,

// чтобы снова сделать -1 (пока =0 они ждут, так как <0 быть не может)

semop(sem_id, &sem_file_in, 1);

}

else

{

sem_id = semget(sem_key, nProg, IPC_CREAT); // открываем семафор

if (sem_id == -1){

cout << "Семафор не был открыт процессом id=" << getpid() << "\n";

exit(-1);

}

cout << "Семафор id=" << sem_id << " открыт процессом id=" << getpid() << "\n";

}

// увеличиваем количество активных процессов

semop(sem_id, &sem_proc_in, 1);

cout << "Текущее количество работающих программ " << semctl(sem_id, 3, GETVAL, 0) << "\n\n";

for (int i = 0; i < atoi(argv[1]); i++) // начинаем запись в файл

{

cout << "Итерация на запись writer'ом строки " << i + 1 << " началась\n";

//cout << "Увеличиваем число активных writer'ов в семафоре процессом id=" << getpid() << "\n";

semop(sem_id, &sem_writer_in, 1);

//cout << "Ждём окончания всех активных reader'ов в семафоре процессом id=" << getpid() << "\n";

semop(sem_id, &sem_reader_com, 1);

// cout << "Уменьшаем возможность доступа к файлу в семафоре процессом id=" << getpid() << " и ЖДЁМ остальных\n";

// то же самое, что при создании, только здесь идет декремент

semop(sem_id, &sem_file_dec, 1); // уменьшаем семафор файла, чтобы другие не могли получить доступ к файлу

cout << "Открываем файл на запись \"" << file_name << "\" процессом id=" << getpid() << "\n";

file.open(file_name, ios::app);

cout << "Записываем строку " << i + 1 << " процессом id=" << getpid() << "\n" << "Процесс id=" << getpid() << ", строка " << i + 1 << "\n";

file << "Процесс id=" << getpid() << ", строка " << i + 1 << "\n";

cout << "Закрываем файл \"" << file_name << "\" на запись процессом id=" << getpid() << "\n";

file.close();

cout << "Увеличиваем возможность доступа к файлу в семафоре процессом id=" << getpid() << " (возвращаем как было)\n";

semop(sem_id, &sem_file_in, 1); // увеличиваем семафор файла, чтобы другие снова могли получить доступ к файлу (возвращаем всё, как было)

cout << "Уменьшаем число активных writer'ов в семафоре процессом id=" << getpid() << "\n";

semop(sem_id, &sem_writer_dec, 1);

cout << "Итерация на запись writer'ом строки " << i + 1 << " завершена\n\n";

sleep(atoi(argv[2])); // ждём указанное в качестве аргумента время

}

// уменьшаю количество активных процессов в семафоре на 1

// в итоге у самой последней программы после этого шага будет 0, и она всё удалит

semop(sem_id, &sem_proc_dec, 1);

// сравниваю количество процессов (если == 0, то захожу, если нет, пропускаю)

if (semctl(sem_id, 3, GETVAL, 0) == 0)

{

semctl(sem_id, IPC_RMID, 0); // удаляю семафор последней программой (последний процесс удаляет все 4 семафора)

cout << "Семафор id=" << sem_id << " удалён\n\n";

}

return 0;

}

Текст reader.cpp

// ./reader

#include <iostream>

#include <fstream>

#include <string>

#include <sys/ipc.h>

#include <sys/sem.h>

#include <unistd.h>

/*

Номер семаформа в множественном семафоре:

0-й -- для файла (для отслеживания писателей, которые хотят писать)

1-й -- количество писателей, которые хотят записать

2-й -- количество читателей, которые хотят прочитать

3-й -- общее количество работающих программ

*/

using namespace std;

int sem_key = 420; // ключ для создания/открытия семафора

int nProg = 4;

string file_name = "file.txt"; // имя файла, чтобы записывать/считывать

struct sembuf sem_file_dec = {0, -1, 0}; // уменьшаем семафор на 1, отвечающий за доступ 1-го писателя к файлу

struct sembuf sem_file_in = {0, 1, 0}; // увеличиваем семафор на 1, отвечающий за доступ 1-го писателя к файлу

struct sembuf sem_writer_com = {1, 0, 0}; // сравниваем активных писателей с 0 и ждём, пока они станут =0

struct sembuf sem_writer_dec = {1, -1, 0}; // уменьшаем семафор на 1, отвечающий за активных писателей

struct sembuf sem_writer_in = {1, 1, 0}; // увеличиваем семафор на 1, отвечающий за активных писателей

struct sembuf sem_reader_com = {2, 0, 0}; // сравниваем активных читателей с 0 и ждём, пока они станут =0

struct sembuf sem_reader_dec = {2, -1, 0}; // уменьшаем семафор на 1, отвечающий за активных читателей

struct sembuf sem_reader_in = {2, 1, 0}; // увеличиваем семафор на 1, отвечающий за активных читателей

struct sembuf sem_proc_dec = {3, -1, 0}; // уменьшаем семафор на 1, отвечающий за число активных программ

struct sembuf sem_proc_in = {3, 1, 0}; // увеличиваем семафор на 1, отвечающий за число активных программ

using namespace std;

int main ()

{

int sem_id; // ID семафора, возвращаемый при создании/открытии

char file_buf[80]; // буфер для чтения файла

ifstream file; // файл для чтения

cout << "Процесс id=" << getpid() << "\n" << "Имя файла " << file_name << "\n" << "Ключ семафора " << sem_key << "\n";

// semget(ключ семафора, количество семафоров в наборе (4 штуки), флаги для создания семафора и с правом доступа у всех)

sem_id = semget(sem_key, nProg, IPC_CREAT | IPC_EXCL | 0666); // создаём множественный семафор

if (sem_id != -1)

{

cout << "Семафор id=" << sem_id << " создан процессом id=" << getpid() << "\n";

// при создании семафора увеличиваем его на 1

// этот семафор нужен только для писателей; для отслеживания возможности записи в файл в данный момент

// при входе в цикл делаем -1, и тогда он будет = 0 (потому что он уже +1 ПРИ создании), поэтому остальные (писатели) не могут сделать -1 в цикле

// так как не стоит флаг IPC_NOWAIT, который сразу возвращает ошибку,

// и остальные программы вынуждены ждать, пока семафор будет =1,

// чтобы снова сделать -1 (пока =0 они ждут, так как <0 быть не может)

semop(sem_id, &sem_file_in, 1);

}

else

{

sem_id = semget(sem_key, nProg, IPC_CREAT); // открываем семафор

if (sem_id == -1){

cout << "Семафор не был открыт процессом id=" << getpid() << "\n";

exit(-1);

}

cout << "Семафор id=" << sem_id << " открыт процессом id=" << getpid() << "\n";

}

// увеличиваем количество активных процессов

semop(sem_id, &sem_proc_in, 1);

cout << "Текущее количество работающих программ " << semctl(sem_id, 3, GETVAL, 0) << "\n\n";

// начинаем чтение из файла

cout << "Ждём окончания всех активных writer'ов в семафоре процессом id=" << getpid() << "\n";

semop(sem_id, &sem_writer_com, 1);

cout << "Увеличиваем число активных reader'ов в семафоре процессом id=" << getpid() << "\n";

semop(sem_id, &sem_reader_in, 1);

// здесь мы ждём только писателей, но не отслеживаем других читателей

// (как это было сделано у писателей с семафором, у которого при создании выставляется 1),

// потому что чтение этого не требует (в отличие от записи)

// из-за этого и получается ситуация, когда при отсутствии писателей читают все,

// а при наличии писателей в числе готовых, читает только один, так как идёт очередь из процессов,

// и следующим (скорее всего) будет не читатель, а писатель

cout << "Открываем файл на чтение \"" << file_name << "\" процессом id=" << getpid() << "\n";

file.open(file_name);

cout << "Читаем строки процессом id=" << getpid() << "\n";

while (file.getline(file_buf, 80))

{

cout << file_buf << "\n";

sleep(1);

}

cout << "Закрываем файл на чтение \"" << file_name << "\" процессом id=" << getpid() << "\n";

file.close();

cout << "Уменьшаем число активных reader'ов в семафоре процессом id=" << getpid() << "\n\n";

semop(sem_id, &sem_reader_dec, 1);

// уменьшаю количество активных процессов в семафоре на 1

// в итоге у самой последней программы после этого шага будет 0, и она всё удалит

semop(sem_id, &sem_proc_dec, 1);

// сравниваю количество процессов (если=0, то значит захожу, если нет, то пропускаю)

if (semctl(sem_id, 3, GETVAL, 0) == 0)

{

semctl(sem_id, IPC_RMID, 0); // удаляю семафор последней программой (последний процесс удаляет все 4 семафора)

cout << "Семафор id=" << sem_id << " удалён\n\n";

}

return 0;

}

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

2022

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