commit e234a48faf0b48df02ebefd26aa3b3fe5e465351 Author: Sergiotarxz Date: Wed Apr 19 00:32:59 2023 +0200 Adding first commit. diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 0000000..4b78d27 --- /dev/null +++ b/Doxyfile @@ -0,0 +1,7 @@ +GENERATE_HTML=yes +EXTRACT_ALL=yes +RECURSIVE=yes +INPUT=../include +DISABLE_INDEX = YES +GENERATE_TREEVIEW = YES +PROJECT_NAME=dining-philosophers diff --git a/include/philosopher-state.hpp b/include/philosopher-state.hpp new file mode 100644 index 0000000..4cf6093 --- /dev/null +++ b/include/philosopher-state.hpp @@ -0,0 +1,7 @@ +#pragma once +enum class PhilosopherState { + THINKING, + HUNGRY, + EATING, +}; + diff --git a/include/philosopher.hpp b/include/philosopher.hpp new file mode 100644 index 0000000..bad154e --- /dev/null +++ b/include/philosopher.hpp @@ -0,0 +1,63 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +#include +#include + +class Philosopher; + +typedef std::shared_ptr PhilosopherPtr; +typedef std::vector ListOfPhilosophers; +typedef std::shared_ptr ListOfPhilosophersPtr; +extern std::mutex changingForkState; +extern std::mutex printing; + +class Philosopher { +private: + int numberOfPhilosopher; + + PhilosopherState state{PhilosopherState::THINKING}; + + ListOfPhilosophersPtr philosophers; + + void + setState(PhilosopherState state); + + size_t + leftPhilosopherNumber(void); + + size_t + rightPhilosopherNumber(void); + + PhilosopherPtr + leftPhilosopher(void); + + PhilosopherPtr + rightPhilosopher(void); + + void + think(); + + void + takeForks(); + + void + eat(); + + void + putForks(); + +public: + PhilosopherState + getState(); + Philosopher(ListOfPhilosophersPtr philosophers, int numberOfPhilosopher); + std::binary_semaphore hasBothForks{0}; + void startThread(); + void test(); +}; + diff --git a/include/random.hpp b/include/random.hpp new file mode 100644 index 0000000..3b1a4e8 --- /dev/null +++ b/include/random.hpp @@ -0,0 +1,4 @@ +#pragma once +#include +size_t +random(size_t min, size_t max); diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..0feea22 --- /dev/null +++ b/meson.build @@ -0,0 +1,31 @@ +project('tech.owlcode.dining-philosophers', 'cpp') +add_global_arguments('-std=c++20', '-D_DEFAULT_SOURCE', language : 'cpp') + +inc = include_directories('include') + +sources = [ + 'src/main.cpp', + 'src/random.cpp', + 'src/philosopher.cpp', +] + +inc = [ + 'include' +] + +link_arguments = [ +] + +executable('dining', + sources, + include_directories : inc, + install : true, + link_args : link_arguments, +) +doxygen = find_program('doxygen', required : false) +if doxygen.found() + message('Doxygen found') + run_target('docs', command : [doxygen, meson.source_root() + '/Doxyfile']) +else + warning('Documentation disabled without doxygen') +endif diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..16aeba6 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,46 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +class Philosopher; + +void +findNumberOfPhilosophersInParams(const int argc, char **argv, int *const numberOfPhilosophers); + +int +main(int argc, char **argv) { + ListOfPhilosophersPtr philosophers; + philosophers = ListOfPhilosophersPtr(new ListOfPhilosophers()); + int numberOfPhilosophers = 5; + findNumberOfPhilosophersInParams(argc, argv, &numberOfPhilosophers); + printf("%d philosophers to create.\n", numberOfPhilosophers); + for (int i = 0; i < numberOfPhilosophers; i++) { + printf("Creating philosopher: %d.\n", i); + philosophers->push_back(PhilosopherPtr(new Philosopher(philosophers, i))); + } + std::vector threads; + for (unsigned long int i = 0; i < philosophers->size(); i++) { + std::shared_ptr numberOfPhilosopher(new unsigned long(i)); + threads.push_back(std::jthread([philosophers, numberOfPhilosopher] { + (*philosophers)[*numberOfPhilosopher]->startThread(); + } )); + } +} + +void +findNumberOfPhilosophersInParams(const int argc, char **argv, int *const numberOfPhilosophers) { + if (argc >= 2) { + const char *numberOfPhilosophersAsString = argv[1]; + try { + *numberOfPhilosophers = std::stoi(numberOfPhilosophersAsString, NULL, 10); + } catch (std::exception &ex) { + printf("Unable to read the number of philosophers, continuing\n"); + } + } +} + diff --git a/src/philosopher.cpp b/src/philosopher.cpp new file mode 100644 index 0000000..47c210c --- /dev/null +++ b/src/philosopher.cpp @@ -0,0 +1,99 @@ +#include + +std::mutex changingForkState; +std::mutex printing; +void +Philosopher::setState(PhilosopherState state) { + this->state = state; +} +size_t +Philosopher::leftPhilosopherNumber(void) { + return (numberOfPhilosopher - 1 + philosophers->size()) % philosophers->size(); +} +size_t +Philosopher::rightPhilosopherNumber(void) { + return (numberOfPhilosopher + 1) % philosophers->size(); +} +PhilosopherPtr +Philosopher::leftPhilosopher(void) { + return (*philosophers)[leftPhilosopherNumber()]; +} +PhilosopherPtr +Philosopher::rightPhilosopher(void) { + return (*philosophers)[rightPhilosopherNumber()]; +} +void +Philosopher::think() { + size_t duration = random(100, 1000); + { + std::lock_guard lk{printing}; + std::cout << "Philosopher " << numberOfPhilosopher << " is thinking for " << duration << "." << std::endl; + } + std::this_thread::sleep_for(std::chrono::milliseconds(duration)); +} + +void +Philosopher::takeForks() { + { + std::lock_guard lk{changingForkState}; + setState(PhilosopherState::HUNGRY); + { + std::lock_guard lk{printing}; + std::cout << "Philosopher " << numberOfPhilosopher << " is hungry." << std::endl; + } + test(); + } + hasBothForks.acquire(); +} + +void Philosopher::eat() { + size_t duration = random(100, 1000); + { + std::lock_guard lk{printing}; + std::cout << "Philosopher " << numberOfPhilosopher << " is eating." << std::endl; + } + std::this_thread::sleep_for(std::chrono::milliseconds(duration)); +} + +void Philosopher::putForks() { + std::lock_guard lk{changingForkState}; + state = PhilosopherState::THINKING; + 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 lk{printing}; + std::cout << "Philosopher " << numberOfPhilosopher << " has sit in the table." << std::endl; + } + while (true) { + think(); + takeForks(); + eat(); + putForks(); + } +} + +void +Philosopher::test() { + if (state == PhilosopherState::HUNGRY && + leftPhilosopher()->getState() != PhilosopherState::EATING && + rightPhilosopher()->getState() != PhilosopherState::EATING) { + setState(PhilosopherState::EATING); + hasBothForks.release(); + } +} + diff --git a/src/random.cpp b/src/random.cpp new file mode 100644 index 0000000..f6959f9 --- /dev/null +++ b/src/random.cpp @@ -0,0 +1,10 @@ +#include +#include + +size_t +random(size_t min, size_t max) +{ + static std::mt19937 rnd(std::time(nullptr)); + return std::uniform_int_distribution<>(min, max)(rnd); +} +