Приложение к лабораторной работе (код программы)
// 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 г.
