diff --git a/module2/Homework/CMakeLists.txt b/module2/Homework/CMakeLists.txt
new file mode 100644
index 0000000..1e7f20a
--- /dev/null
+++ b/module2/Homework/CMakeLists.txt
@@ -0,0 +1,16 @@
+cmake_minimum_required(VERSION 3.0)
+
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+set(CMAKE_CXX_COMPILER g++)
+
+add_definitions(-Wno-unused-variable)
+add_definitions(-Wall -Werror -pedantic -Wextra -fsanitize=thread)
+#add_link_options(-fsanitize=thread)
+
+file(GLOB SOURCES *.cpp)
+
+set(BINNAME dining_philosophers)
+add_executable(${BINNAME} ${SOURCES})
+target_link_libraries(${BINNAME} pthread -fsanitize=thread)
+
diff --git a/module2/Homework/dining_table.cpp b/module2/Homework/dining_table.cpp
new file mode 100644
index 0000000..4896975
--- /dev/null
+++ b/module2/Homework/dining_table.cpp
@@ -0,0 +1,75 @@
+#include "philosopher.h"
+#include "dining_table.h"
+
+
+Table::Table(int seats) : seats_(seats) {
+// self_ = std::shared_ptr
(this);
+ wait_for = seats;
+ for (int n = 0; n < seats_; ++n) {
+ forks.emplace_back(std::make_shared(n));
+ }
+ for (int n = 0; n < seats_; ++n) {
+ int r = n;
+ int l = (n+1) % seats_;
+ philosophers.emplace_back(std::make_shared(n, this, forks[r], forks[l]));
+ }
+}
+
+void Table::updateCallback(int id) {
+ std::lock_guard lock(m_update_mtx);
+
+ if (philosophers[id]->getStatus() == PhilStatus::Done) {
+ wait_for--;
+// std::cout << "Philosopher " << id << " reported as done. wait_for = " << wait_for << std::endl;
+
+ }
+
+// std::cout << "Status update from phil id=" << id << std::endl;
+ m_cond_update.notify_one();
+
+}
+
+void Table::drawHeader() {
+ std::stringstream ss;
+ for (auto p: philosophers) {
+ ss << "| Phil " << p->getId() << " ";
+ }
+ ss << std::endl << std::string(philosophers.size() * 12, '-') << std::endl;
+ std::cout << ss.rdbuf();
+}
+
+void Table::drawStatus() {
+ std::stringstream ss;
+ for (auto p: philosophers) {
+ ss << p->readStatus();
+ }
+ ss << std::endl;
+ std::cout << ss.rdbuf();
+}
+
+void Table::joinPhilosopherToTheFeast(std::shared_ptr p) {
+ std::thread t = std::thread(&Philosopher::threadStartTheFeast, &(*p));
+ p->setThread(t);
+ std::cout << "Started " << p->getId() << std::endl;
+}
+
+void Table::Run() {
+ for (auto p: philosophers) {
+ joinPhilosopherToTheFeast(p);
+ }
+ std::cout << "Start monitoring Eating Philosophers" << std::endl;
+ drawHeader();
+ do {
+ std::unique_lock mlock(m_update_mtx);
+ m_cond_update.wait(mlock);
+ drawStatus();
+ } while (wait_for);
+}
+
+
+int main() {
+ Table table(15);
+ table.Run();
+
+ return 0;
+}
diff --git a/module2/Homework/dining_table.h b/module2/Homework/dining_table.h
new file mode 100644
index 0000000..b00dfa0
--- /dev/null
+++ b/module2/Homework/dining_table.h
@@ -0,0 +1,47 @@
+#ifndef _DINING_TABLE_H_
+#define _DINING_TABLE_H_
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "philosopher.h"
+
+class Fork {
+ int id_;
+public:
+ mutable std::mutex mtx_;
+ Fork(int id) : id_(id) {}
+
+};
+
+
+class Table {
+ int seats_;
+ int wait_for;
+ std::shared_ptr self_;
+ std::vector > forks;
+ std::vector > philosophers;
+ std::mutex m_update_mtx;
+ std::condition_variable m_cond_update;
+
+ void drawHeader();
+ void drawStatus();
+ void joinPhilosopherToTheFeast(std::shared_ptr p);
+public:
+ Table(int seats);
+ void updateCallback(int id);
+ void Run();
+ int seats() { return seats_; }
+};
+
+
+#endif // _DINING_TABLE_H_
\ No newline at end of file
diff --git a/module2/Homework/philosopher.cpp b/module2/Homework/philosopher.cpp
new file mode 100644
index 0000000..d473d50
--- /dev/null
+++ b/module2/Homework/philosopher.cpp
@@ -0,0 +1,88 @@
+#include "philosopher.h"
+#include "dining_table.h"
+
+using namespace std::chrono_literals;
+
+EatTimeEngine* EatTimeEngine::pinstance_{nullptr};
+std::mutex EatTimeEngine::mutex_;
+
+EatTimeEngine* EatTimeEngine::GetInstance()
+{
+ std::lock_guard lock(mutex_);
+ if(pinstance_ == 0)
+ {
+ std::random_device rd;
+ pinstance_ = new EatTimeEngine(rd());
+ }
+ return pinstance_;
+}
+
+/* ***********************************************************
+ class Philosopher
+ *********************************************************** */
+std::string Philosopher::readStatus() {
+ std::lock_guard lock(mtx_);
+ std::string s;
+ switch (status_)
+ {
+ case PhilStatus::Done:
+ s = "| ****** ";
+ break;
+ case PhilStatus::Eating:
+ s = "| Eating ";
+ break;
+ default:
+ s = "| ";
+ break;
+ }
+ return s;
+}
+
+PhilStatus Philosopher::getStatus() {
+ std::lock_guard lock(mtx_);
+ return status_;
+}
+
+void Philosopher::startEating()
+{
+ std::lock_guard lock(mtx_);
+ status_ = PhilStatus::Eating;
+}
+
+void Philosopher::stopEating() {
+ std::lock_guard lock(mtx_);
+ status_ = PhilStatus::Thinking;
+}
+
+void Philosopher::finished() {
+ {
+ std::lock_guard lock(mtx_);
+ status_ = PhilStatus::Done;
+ }
+// std::stringstream ss;
+// ss << "Philosopher " << id_ << " finished " << quota << " dishes." << std::endl;
+// std::cout << ss.rdbuf();
+ p_table->updateCallback(id_);
+}
+
+void Philosopher::threadStartTheFeast() {
+ int counter = this->quota;
+ std::stringstream ss;
+
+ while(counter--) {
+ int t;
+
+ {
+ std::scoped_lock both_forks(fork_r->mtx_, fork_l->mtx_);
+ startEating();
+ t = lottery->pickTime();
+ p_table->updateCallback(id_);
+ std::this_thread::sleep_for(t * 10ms);
+ }
+
+ stopEating(); // Eating finished
+ p_table->updateCallback(id_);
+
+ }
+ finished();
+}
diff --git a/module2/Homework/philosopher.h b/module2/Homework/philosopher.h
new file mode 100644
index 0000000..d660f01
--- /dev/null
+++ b/module2/Homework/philosopher.h
@@ -0,0 +1,100 @@
+#ifndef _PHILOSOPHER_H_
+#define _PHILOSOPHER_H_
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+class EatTimeEngine
+{
+private:
+ std::mt19937 m_generator;
+ std::uniform_int_distribution m_distribution;
+ static EatTimeEngine *pinstance_;
+ static std::mutex mutex_;
+protected:
+ EatTimeEngine(std::random_device::result_type seed) : m_generator(seed), m_distribution(1, 100) {}
+ ~EatTimeEngine() {}
+public:
+ int pickTime() {
+ std::lock_guard lock(mutex_);
+ return m_distribution(m_generator);
+ }
+ static EatTimeEngine* GetInstance();
+ EatTimeEngine(EatTimeEngine &other) = delete; // Singletons should not be cloneable.
+ void operator=(const EatTimeEngine &) = delete; // Singletons should not be assignable.
+};
+
+/* ********************************************************************** */
+enum class PhilStatus {
+ Eating, Thinking, Done
+};
+
+class Table;
+class Fork;
+
+class Philosopher {
+private:
+ int id_;
+ const int quota = 6; // How many dishes every philosopher must eat
+ EatTimeEngine* lottery;
+ std::thread m_t;
+ mutable std::mutex mtx_;
+ PhilStatus status_;
+ Table* p_table;
+ std::shared_ptr fork_r, fork_l;
+
+ void startEating();
+ void stopEating();
+ void finished();
+public:
+ Philosopher(int id, Table* t, std::shared_ptr &right, std::shared_ptr &left) :
+ id_(id),
+ status_(PhilStatus::Thinking),
+ p_table(t),
+ fork_r(right),
+ fork_l(left) {
+ lottery = EatTimeEngine::GetInstance();
+ }
+
+ ~Philosopher() {
+ std::lock_guard lock(mtx_);
+ if (m_t.joinable()) {
+ m_t.join();
+ }
+ }
+
+ Philosopher(const Philosopher&) = delete; //Delete the copy constructor
+ Philosopher& operator=(const Philosopher&) = delete; //Delete the Assignment opeartor
+
+ std::string readStatus();
+ PhilStatus getStatus();
+ void threadStartTheFeast();
+
+ void setThread(std::thread &t) {
+ m_t = std::move(t);
+ }
+
+ void endThread() {
+ std::lock_guard lock(mtx_);
+ if (m_t.joinable()) {
+ m_t.join();
+ }
+ }
+
+ int getId() {
+ std::lock_guard lock(mtx_);
+ return id_;
+ }
+};
+
+#endif //_DINING_TABLE_H_