Untitled

 avatar
unknown
plain_text
15 days ago
4.4 kB
2
Indexable
#include <iostream>
#include <thread>
#include <mutex>
#include <vector>
#include <ncurses.h>
#include <unistd.h>
#include <condition_variable>

using namespace std;

// Liczba filozofów
int NUM_PHILOSOPHERS;

// Mutex chroniący dostęp do stołu
mutex table_mutex;

// Wektory przechowujące mutexy dla widelców
vector<unique_ptr<mutex>> forks;

// Mutex do synchronizacji wyjścia NCurses
mutex output_mtx;

// Licznik liczby posiłków dla każdego filozofa
vector<int> eating_count;

// Wektor przechowujący informację, czy filozof może jeść
vector<bool> can_eat;

// Stany filozofów: MYŚLENIE lub JEDZENIE
enum State { THINKING, EATING };
vector<State> philosopher_state;

// Mutex i zmienna warunkowa do synchronizacji kelnera
std::mutex waiter_mutex;
std::condition_variable waiter_cv;
int eating_philosophers = 0;

// Konwersja stanu filozofa na string
string state_to_string(State state) {
    return state == THINKING ? "MYSLI" : "JE";
}

// Funkcja wyświetlająca aktualny stan filozofów w terminalu
void printStatus() {
    lock_guard<mutex> lock(output_mtx); // Zabezpieczenie przed równoczesnym dostępem do ekranu
    lock_guard<mutex> table_lock(table_mutex); // Zabezpieczenie przed równoczesnym odczytem danych
    
    clear(); // Czyszczenie ekranu ncurses
    mvprintw(0, 0, "FILOZOF:"); // Nagłówek kolumny z numerami filozofów
    mvprintw(0, 10, "STAN:"); // Nagłówek kolumny ze stanami filozofów
    mvprintw(0, 40, "LICZNIK NAJEDZENIA:"); // Nagłówek kolumny z licznikami posiłków
    
    for (int i = 0; i < NUM_PHILOSOPHERS; i++) {
        mvprintw(i + 1, 0, "%d.", i + 1); // Wyświetlenie numeru filozofa
        mvprintw(i + 1, 10, "%s", state_to_string(philosopher_state[i]).c_str()); // Wyświetlenie aktualnego stanu filozofa
        mvprintw(i + 1, 40, "%d", eating_count[i]); // Wyświetlenie licznika liczby posiłków
    }
    
    refresh(); // Odświeżenie ekranu ncurses, aby zmiany były widoczne
}

// Funkcja zmieniająca stan filozofa z zachowaniem synchronizacji
void change_state(int id, State state) {
    lock_guard<mutex> lock(table_mutex);
    philosopher_state[id] = state;
}

// Funkcja symulująca zachowanie filozofa
void philosopher(int id) {
    while (eating_count[id] < 100) { // Filozof działa, dopóki nie zje 100 razy
        change_state(id, THINKING);
        printStatus();
        this_thread::sleep_for(chrono::milliseconds(rand() % 1000 + 500));

        unique_lock<mutex> waiter_lock(waiter_mutex);
        waiter_cv.wait(waiter_lock, [id] {
            return !can_eat[(id + NUM_PHILOSOPHERS - 1) % NUM_PHILOSOPHERS] &&  
                   !can_eat[(id + 1) % NUM_PHILOSOPHERS];  
        });

        eating_philosophers++;
        can_eat[id] = true;
        waiter_lock.unlock();

        // Podnoszenie widelcow
        lock_guard<mutex> left_fork_lock(*forks[id]);
        lock_guard<mutex> right_fork_lock(*forks[(id + 1) % NUM_PHILOSOPHERS]);

        change_state(id, EATING);
        eating_count[id]++;
        printStatus();
        this_thread::sleep_for(chrono::milliseconds(rand() % 1000 + 500));

        waiter_lock.lock();
        eating_philosophers--;
        can_eat[id] = false;
        waiter_cv.notify_all();
    }
}

void display()
{
	while(true)
	{
		printStatus();
		usleep(250000);
	}
}

int main(int argc, char* argv[]) {
    if (argc != 2) {
        cerr << "Usage: " << argv[0] << " <number_of_philosophers>" << endl;
        return 1;
    }

    NUM_PHILOSOPHERS = stoi(argv[1]);

    if (NUM_PHILOSOPHERS < 2) {
        cerr << "Number of philosophers must be at least 2." << endl;
        return 1;
    }

    forks.resize(NUM_PHILOSOPHERS);
    for (int i = 0; i < NUM_PHILOSOPHERS; i++) {
        forks[i] = make_unique<mutex>();
    }

    eating_count.resize(NUM_PHILOSOPHERS, 0);
    philosopher_state.resize(NUM_PHILOSOPHERS, THINKING);
    can_eat.resize(NUM_PHILOSOPHERS, false);

    initscr();
    noecho();
    curs_set(FALSE);

    vector<thread> philosophers;
    for (int i = 0; i < NUM_PHILOSOPHERS; i++) {
        philosophers.push_back(thread(philosopher, i));
    }

    thread display_thread(display);

    for (auto& p : philosophers) {
        p.join();
    }

    display_thread.join();
    endwin();
    getch(); // Oczekiwanie na naciśnięcie klawisza przed zamknięciem programu
    return 0;
}
Leave a Comment