Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лабораторные. Дагаев / Операционные_системы_ЛР_№5_Отчет.docx
Скачиваний:
1
Добавлен:
02.01.2026
Размер:
58.58 Кб
Скачать

Приложение к лабораторной работе (код программы)

// process_sync_linux.cpp

// Компиляция: g++ -o process_sync process_sync_linux.cpp -lpthread -lrt -std=c++11

#include <iostream>

#include <string>

#include <thread>

#include <chrono>

#include <random>

#include <cstring>

#include <cstdlib>

#include <unistd.h>

#include <fcntl.h>

#include <sys/mman.h>

#include <sys/stat.h>

#include <semaphore.h>

#include <signal.h>

// Структура для разделяемой памяти

struct SharedData {

    double temperature;

    int reader_count;

    bool stop_flag;

};

// Глобальные указатели и дескрипторы

SharedData* shared_data = NULL;

int shm_fd = -1;

const char* shm_name = "/temperature_shm";

// Семафоры POSIX

sem_t* mutex = SEM_FAILED;           // Для взаимоисключения доступа к reader_count

sem_t* write_sem = SEM_FAILED;       // Для блокировки писателя

sem_t* stop_sem = SEM_FAILED;        // Для остановки всех процессов

// Функция инициализации общих объектов

bool InitializeSharedObjects() {

    // Создаем или открываем разделяемую память

    shm_fd = shm_open(shm_name, O_CREAT | O_RDWR, 0666);

    if (shm_fd == -1) {

        std::cerr << "shm_open failed: " << strerror(errno) << std::endl;

        return false;

    }

   

    // Устанавливаем размер разделяемой памяти

    if (ftruncate(shm_fd, sizeof(SharedData)) == -1) {

        std::cerr << "ftruncate failed: " << strerror(errno) << std::endl;

        return false;

    }

   

    // Проецируем разделяемую память в адресное пространство

    shared_data = (SharedData*)mmap(NULL, sizeof(SharedData),

                                    PROT_READ | PROT_WRITE,

                                    MAP_SHARED, shm_fd, 0);

   

    if (shared_data == MAP_FAILED) {

        std::cerr << "mmap failed: " << strerror(errno) << std::endl;

        return false;

    }

   

    // Инициализируем данные, если создаем впервые

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

    struct stat st;

    if (fstat(shm_fd, &st) == 0 && st.st_size == 0) {

        shared_data->temperature = 20.0;

        shared_data->reader_count = 0;

        shared_data->stop_flag = false;

        std::cout << "Shared memory initialized for the first time" << std::endl;

    } else {

        std::cout << "Connected to existing shared memory" << std::endl;

    }

   

    // Создаем/открываем именованные семафоры

    // O_CREAT | O_EXCL создаст только если не существует

    mutex = sem_open("/temp_mutex", O_CREAT | O_RDWR, 0666, 1);

    if (mutex == SEM_FAILED) {

        std::cerr << "sem_open(mutex) failed: " << strerror(errno) << std::endl;

        // Пробуем просто открыть, если уже создан

        mutex = sem_open("/temp_mutex", O_RDWR);

        if (mutex == SEM_FAILED) {

            return false;

        }

    }

   

    write_sem = sem_open("/temp_write_sem", O_CREAT | O_RDWR, 0666, 1);

    if (write_sem == SEM_FAILED) {

        std::cerr << "sem_open(write_sem) failed: " << strerror(errno) << std::endl;

        write_sem = sem_open("/temp_write_sem", O_RDWR);

        if (write_sem == SEM_FAILED) {

            return false;

        }

    }

   

    stop_sem = sem_open("/temp_stop_sem", O_CREAT | O_RDWR, 0666, 0);

    if (stop_sem == SEM_FAILED) {

        std::cerr << "sem_open(stop_sem) failed: " << strerror(errno) << std::endl;

        stop_sem = sem_open("/temp_stop_sem", O_RDWR);

        if (stop_sem == SEM_FAILED) {

            return false;

        }

    }

   

    return true;

}

// Функция очистки

void Cleanup() {

    if (shared_data && shared_data != MAP_FAILED) {

        munmap(shared_data, sizeof(SharedData));

    }

   

    if (shm_fd != -1) {

        close(shm_fd);

    }

   

    if (mutex != SEM_FAILED) {

        sem_close(mutex);

    }

   

    if (write_sem != SEM_FAILED) {

        sem_close(write_sem);

    }

   

    if (stop_sem != SEM_FAILED) {

        sem_close(stop_sem);

    }

}

// Функция для полной очистки всех объектов (вызывается при остановке)

void FullCleanup() {

    Cleanup();

   

    // Удаляем именованные объекты

    shm_unlink(shm_name);

    sem_unlink("/temp_mutex");

    sem_unlink("/temp_write_sem");

    sem_unlink("/temp_stop_sem");

}

// Обработчик сигнала для корректного завершения

void SignalHandler(int signum) {

    std::cout << "\nInterrupt signal (" << signum << ") received." << std::endl;

    if (shared_data) {

        shared_data->stop_flag = true;

    }

}

// ==================== ПРОЦЕСС ДАТЧИК (ПИСАТЕЛЬ) ====================

void RunSensor() {

    std::cout << "=== SENSOR Process (Writer) started ===" << std::endl;

    std::cout << "PID: " << getpid() << std::endl;

   

    std::random_device rd;

    std::mt19937 gen(rd());

    std::normal_distribution<> dist(20.0, 5.0); // Нормальное распределение

   

    int update_count = 0;

   

    while (!shared_data->stop_flag && update_count < 10) {

        // Ждем разрешения на запись (семафор со значением 1)

        sem_wait(write_sem);

       

        // Генерируем новую температуру

        double new_temp = dist(gen);

        shared_data->temperature = new_temp;

       

        std::cout << "Sensor wrote: " << new_temp << "C (update "

                  << ++update_count << ")" << std::endl;

       

        // Освобождаем семафор

        sem_post(write_sem);

       

        // Ждем 500мс перед следующим обновлением

        std::this_thread::sleep_for(std::chrono::milliseconds(500));

    }

   

    std::cout << "Sensor finished work" << std::endl;

}

// ==================== ПРОЦЕСС МОНИТОР (ЧИТАТЕЛЬ) ====================

void RunMonitor() {

    std::cout << "=== MONITOR Process (Reader) started ===" << std::endl;

    std::cout << "PID: " << getpid() << std::endl;

   

    int read_count = 0;

   

    while (!shared_data->stop_flag && read_count < 20) {

        // Увеличиваем счетчик читателей (с взаимным исключением)

        sem_wait(mutex);

        shared_data->reader_count++;

        if (shared_data->reader_count == 1) {

            // Первый читатель блокирует писателя

            sem_wait(write_sem);

        }

        sem_post(mutex);

       

        // ЧИТАЕМ данные

        double temp = shared_data->temperature;

        std::cout << "Monitor read: " << temp << "C (readers now: "

                  << shared_data->reader_count << ")" << std::endl;

       

        // Уменьшаем счетчик читателей

        sem_wait(mutex);

        shared_data->reader_count--;

        if (shared_data->reader_count == 0) {

            // Последний читатель освобождает писателя

            sem_post(write_sem);

        }

        sem_post(mutex);

       

        read_count++;

        std::this_thread::sleep_for(std::chrono::milliseconds(300));

    }

   

    std::cout << "Monitor finished work" << std::endl;

}

// ==================== ПРОЦЕСС АНАЛИЗАТОР (ЧИТАТЕЛЬ) ====================

void RunAnalyzer(int id) {

    std::cout << "=== ANALYZER Process #" << id << " started ===" << std::endl;

    std::cout << "PID: " << getpid() << std::endl;

   

    double min_temp = 1000;

    double max_temp = -1000;

    int readings = 0;

   

    while (!shared_data->stop_flag && readings < 15) {

        // Увеличиваем счетчик читателей

        sem_wait(mutex);

        shared_data->reader_count++;

        if (shared_data->reader_count == 1) {

            sem_wait(write_sem);

        }

        sem_post(mutex);

       

        // Читаем и анализируем

        double temp = shared_data->temperature;

        if (temp < min_temp) min_temp = temp;

        if (temp > max_temp) max_temp = temp;

        readings++;

       

        std::cout << "Analyzer #" << id << ": " << temp << "C (min="

                  << min_temp << ", max=" << max_temp << ")" << std::endl;

       

        // Уменьшаем счетчик читателей

        sem_wait(mutex);

        shared_data->reader_count--;

        if (shared_data->reader_count == 0) {

            sem_post(write_sem);

        }

        sem_post(mutex);

       

        std::this_thread::sleep_for(std::chrono::milliseconds(400 + id * 100));

    }

   

    std::cout << "Analyzer #" << id << " finished. Range: "

              << min_temp << " - " << max_temp << std::endl;

}

// ==================== ОСНОВНАЯ ФУНКЦИЯ ====================

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

    // Устанавливаем обработчик сигналов для корректного завершения

    signal(SIGINT, SignalHandler);

    signal(SIGTERM, SignalHandler);

   

    // Параметр командной строки определяет тип процесса

    std::string role = "monitor";  // по умолчанию

    if (argc > 1) {

        role = argv[1];

    }

   

    // Инициализируем общие объекты

    if (!InitializeSharedObjects()) {

        std::cerr << "Initialization error" << std::endl;

        return 1;

    }

   

    std::cout << "Process role: " << role << std::endl;

   

    // Проверяем, не нужно ли остановиться

    int sem_value;

    sem_getvalue(stop_sem, &sem_value);

    if (sem_value > 0) {

        std::cout << "Received stop signal" << std::endl;

        Cleanup();

        return 0;

    }

   

    // Запускаем соответствующую функцию

    if (role == "sensor") {

        RunSensor();

    }

    else if (role == "monitor") {

        RunMonitor();

    }

    else if (role == "analyzer1") {

        RunAnalyzer(1);

    }

    else if (role == "analyzer2") {

        RunAnalyzer(2);

    }

    else if (role == "stop") {

        // Команда остановки всех процессов

        std::cout << "Sending stop signal to all processes..." << std::endl;

       

        // Устанавливаем флаг остановки

        if (shared_data) {

            shared_data->stop_flag = true;

        }

       

        // Сигнализируем через семафор

        sem_post(stop_sem);

       

        // Ждем 2 секунды

        std::this_thread::sleep_for(std::chrono::seconds(2));

       

        // Полная очистка объектов

        FullCleanup();

    }

    else if (role == "clean") {

        // Только очистка объектов (если что-то осталось с предыдущих запусков)

        std::cout << "Cleaning up shared objects..." << std::endl;

        FullCleanup();

        std::cout << "Cleanup completed" << std::endl;

        return 0;

    }

    else {

        std::cout << "Unknown role. Use: sensor, monitor, analyzer1, analyzer2, stop, clean" << std::endl;

        std::cout << "Examples:" << std::endl;

        std::cout << "  ./process_sync sensor" << std::endl;

        std::cout << "  ./process_sync monitor" << std::endl;

        std::cout << "  ./process_sync analyzer1" << std::endl;

        std::cout << "  ./process_sync analyzer2" << std::endl;

        std::cout << "  ./process_sync stop     # stop all processes" << std::endl;

        std::cout << "  ./process_sync clean    # cleanup leftover objects" << std::endl;

    }

   

    Cleanup();

    return 0;

}

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

2025 г.