dining-philosophers/src/philosopher.cpp

128 lines
3.8 KiB
C++
Raw Normal View History

2023-04-19 00:32:59 +02:00
#include <philosopher.hpp>
std::mutex changingForkState;
std::mutex printing;
void
Philosopher::setState(PhilosopherState state) {
this->state = state;
}
size_t
Philosopher::leftPhilosopherNumber(void) {
2023-04-19 01:28:50 +02:00
// Circular implementation of the table to the left.
// (0 - 1 + 9) % 9 = 8
// (1 - 1 + 9) % 9 = 0
2023-04-19 00:32:59 +02:00
return (numberOfPhilosopher - 1 + philosophers->size()) % philosophers->size();
}
size_t
Philosopher::rightPhilosopherNumber(void) {
2023-04-19 01:28:50 +02:00
// Circular implementation of the table to the right.
// (8 + 1) % 9 = 0
// (7 + 1) % 9 = 8
2023-04-19 00:32:59 +02:00
return (numberOfPhilosopher + 1) % philosophers->size();
}
2023-04-19 01:28:50 +02:00
2023-04-19 00:32:59 +02:00
PhilosopherPtr
Philosopher::leftPhilosopher(void) {
return (*philosophers)[leftPhilosopherNumber()];
}
2023-04-19 01:28:50 +02:00
2023-04-19 00:32:59 +02:00
PhilosopherPtr
Philosopher::rightPhilosopher(void) {
return (*philosophers)[rightPhilosopherNumber()];
}
2023-04-19 01:28:50 +02:00
2023-04-19 00:32:59 +02:00
void
Philosopher::think() {
2023-04-19 01:28:50 +02:00
// The number of milliseconds thinking.
2023-04-19 00:32:59 +02:00
size_t duration = random(100, 1000);
{
2023-04-19 01:28:50 +02:00
// Holds the lock for printing.
2023-04-19 00:32:59 +02:00
std::lock_guard<std::mutex> lk{printing};
std::cout << "Philosopher " << numberOfPhilosopher << " is thinking for " << duration << "." << std::endl;
}
2023-04-19 01:28:50 +02:00
// Sleeps.
2023-04-19 00:32:59 +02:00
std::this_thread::sleep_for(std::chrono::milliseconds(duration));
}
void
Philosopher::takeForks() {
{
2023-04-19 01:28:50 +02:00
// Holds the lock for state manipulation and read.
2023-04-19 00:32:59 +02:00
std::lock_guard<std::mutex> lk{changingForkState};
2023-04-19 01:28:50 +02:00
// Sets the philosopher to be hungry.
2023-04-19 00:32:59 +02:00
setState(PhilosopherState::HUNGRY);
{
2023-04-19 01:28:50 +02:00
// Holds the lock for printing.
2023-04-19 00:32:59 +02:00
std::lock_guard<std::mutex> lk{printing};
std::cout << "Philosopher " << numberOfPhilosopher << " is hungry." << std::endl;
}
2023-04-19 01:28:50 +02:00
// Attempts to release the binary semaphore for forks locking if still up.
2023-04-19 00:32:59 +02:00
test();
}
2023-04-19 01:28:50 +02:00
// Attempts to adquire the forks lock.
2023-04-19 00:32:59 +02:00
hasBothForks.acquire();
}
void Philosopher::eat() {
2023-04-19 01:28:50 +02:00
// Sets the time eating.
2023-04-19 00:32:59 +02:00
size_t duration = random(100, 1000);
{
2023-04-19 01:28:50 +02:00
// Holds the lock for printing.
2023-04-19 00:32:59 +02:00
std::lock_guard<std::mutex> lk{printing};
std::cout << "Philosopher " << numberOfPhilosopher << " is eating." << std::endl;
}
2023-04-19 01:28:50 +02:00
// Sleeps the time the philosopher last to eat.
2023-04-19 00:32:59 +02:00
std::this_thread::sleep_for(std::chrono::milliseconds(duration));
}
void Philosopher::putForks() {
2023-04-19 01:28:50 +02:00
// Holds the lock for state manipulation and read.
2023-04-19 00:32:59 +02:00
std::lock_guard<std::mutex> lk{changingForkState};
2023-04-19 01:28:50 +02:00
// Set the philosopher in thinking state.
setState(PhilosopherState::THINKING);
2023-04-19 01:40:22 +02:00
// Attempts to free the lock of neighbors if they are locked because of this philosopher.
2023-04-19 00:32:59 +02:00
leftPhilosopher()->test();
rightPhilosopher()->test();
}
PhilosopherState
Philosopher::getState() {
return state;
}
Philosopher::Philosopher(ListOfPhilosophersPtr philosophers, int numberOfPhilosopher):
state(PhilosopherState::THINKING) {
this->numberOfPhilosopher = numberOfPhilosopher;
this->philosophers = philosophers;
}
void
Philosopher::startThread() {
{
std::lock_guard<std::mutex> lk{printing};
std::cout << "Philosopher " << numberOfPhilosopher << " has sit in the table." << std::endl;
}
while (true) {
2023-04-19 01:28:50 +02:00
// The philosopher starts thinking.
2023-04-19 00:32:59 +02:00
think();
2023-04-19 01:28:50 +02:00
// Then gets hungry and attempts to eat.
2023-04-19 00:32:59 +02:00
takeForks();
2023-04-19 01:28:50 +02:00
// When the two forks are available the philosopher eats.
2023-04-19 00:32:59 +02:00
eat();
2023-04-19 01:40:22 +02:00
// Then the philosopher puts the two forks on the table to be used by the philosopher's neighbors.
2023-04-19 00:32:59 +02:00
putForks();
}
}
void
Philosopher::test() {
2023-04-19 01:28:50 +02:00
// This is self-documenting.
2023-04-19 00:32:59 +02:00
if (state == PhilosopherState::HUNGRY &&
leftPhilosopher()->getState() != PhilosopherState::EATING &&
rightPhilosopher()->getState() != PhilosopherState::EATING) {
setState(PhilosopherState::EATING);
hasBothForks.release();
}
}