Untitled
#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(); return 0; }
Leave a Comment