Advertisement
EWTD

Dijkstra's dining philosophers problem solution

Dec 27th, 2022
1,101
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 5.25 KB | None | 0 0
  1. #include <iostream>
  2. #include <vector>
  3. #include <list>
  4. #include <mutex>
  5. #include <atomic>
  6. #include <thread>
  7. #include <chrono>
  8. #include <ctime>
  9. #include <iomanip>
  10. #include <matplot/matplot.h>
  11. using namespace std::chrono_literals;
  12. using namespace matplot;
  13.  
  14. class Worker{
  15. public:
  16.     enum State: std::uint8_t {
  17.         None = 255,
  18.         Working = 0,
  19.         Thinking = 1,
  20.         TakingLeftResource = 2,
  21.         TakingRightResource = 3,
  22.         ReleasingResources = 4
  23.     };
  24. private:
  25.     std::array<std::uint32_t, 5> _state_duration;
  26.     std::mutex& _min_resource;
  27.     std::mutex& _max_resource;
  28.     std::atomic_bool is_cancellation_requested;
  29.     std::list<std::pair<State, std::uint32_t>> _log;
  30.     std::chrono::time_point<std::chrono::steady_clock> _start;
  31.     std::uint32_t _duration;
  32. public:
  33.     Worker(std::mutex& min_resource, std::mutex& max_resource):
  34.     _min_resource(min_resource), _max_resource(max_resource)
  35.     {
  36.         for(auto& elem: _state_duration)
  37.             elem = (rand() % 4 + 1) * 1000;
  38.     }
  39.  
  40.     void run(){
  41.         is_cancellation_requested.store(false);
  42.         _start = std::chrono::steady_clock::now();
  43.         _duration = 0;
  44.         while(!is_cancellation_requested.load()){
  45.             __log(Thinking);
  46.             std::this_thread::sleep_for(std::chrono::milliseconds(__get_state_duration(Thinking)));
  47.             if(is_cancellation_requested.load()) break;
  48.             _min_resource.lock();
  49.             __log(TakingLeftResource);
  50.             if(is_cancellation_requested.load()) {_min_resource.unlock(); break;}
  51.             _max_resource.lock();
  52.             __log(TakingRightResource);
  53.             if(is_cancellation_requested.load()) {_min_resource.unlock(); _max_resource.unlock(); break;}
  54.             std::this_thread::sleep_for(std::chrono::milliseconds(__get_state_duration(Working)));
  55.             __log(Working);
  56.             if(is_cancellation_requested.load()) {_min_resource.unlock(); _max_resource.unlock(); break;}
  57.             _max_resource.unlock();
  58.             _min_resource.unlock();
  59.         }
  60.     }
  61.  
  62.     std::list<std::pair<Worker::State, std::uint32_t>> stop() noexcept{
  63.         std::list<std::pair<Worker::State, std::uint32_t>> result = _log;
  64.         is_cancellation_requested.store(true);
  65.         _log.clear();
  66.         return result;
  67.     }
  68. private:
  69.     inline uint32_t __get_state_duration(const State state) const noexcept{
  70.         if (state == Working || state == Thinking)
  71.             return _state_duration[static_cast<uint8_t>(state)];
  72.         else
  73.             return std::chrono::duration_cast<std::chrono::milliseconds>(
  74.                     std::chrono::steady_clock::now() - (_start + std::chrono::milliseconds(_duration))
  75.                     ).count();
  76.     }
  77.  
  78.     void __log(const State state) noexcept{
  79.         const float duration = __get_state_duration(state);
  80.         _duration += duration;
  81.         _log.emplace_back(state, duration);
  82.     }
  83. };
  84.  
  85. class WorkerPool{
  86.     std::vector<std::mutex> _resource;
  87.     std::vector<Worker*> _workers;
  88.     std::vector<std::thread> _threads;
  89. public:
  90.  
  91.     WorkerPool(std::uint8_t size): _resource(size){
  92.         for(std::uint8_t idx = 0; idx < size; idx++)
  93.             if (idx != size - 1)
  94.                 _workers.push_back(new Worker(_resource[idx], _resource[idx + 1]));
  95.             else
  96.                 _workers.push_back(new Worker(_resource[0], _resource[idx]));
  97.     }
  98.  
  99.     void start(){
  100.         for(std::uint8_t idx = 0; idx < _workers.size(); idx++)
  101.             _threads.emplace_back(&Worker::run, _workers[idx] );
  102.     }
  103.  
  104.     std::vector<std::list<std::pair<Worker::State, uint32_t>>> stop(){
  105.         std::vector<std::list<std::pair<Worker::State, uint32_t>>> result;
  106.         for(auto& worker: _workers)
  107.             result.push_back(worker->stop());
  108.         for(auto& th: _threads)
  109.             if(th.joinable()) th.join();
  110.         for(auto& worker: _workers)
  111.             delete worker;
  112.         return result;
  113.     }
  114. };
  115. auto get_color(const Worker::State state){
  116.     if (state == Worker::Working)
  117.         return color::green;
  118.     if (state == Worker::Thinking)
  119.         return color::red;
  120.     if (state == Worker::TakingRightResource)
  121.         return color::magenta;
  122.     if (state == Worker::TakingLeftResource)
  123.         return color::blue;
  124. }
  125.  
  126. int main(int argc, char** argv){
  127.     std::srand(std::time(nullptr));
  128.     WorkerPool pool(5);
  129.     pool.start();
  130.     char input;
  131.     for(;;){
  132.         std::cin >> input;
  133.         if(input == 'q' || input == 'Q') break;
  134.     }
  135.     auto log = pool.stop();
  136.  
  137.     auto t = std::time(nullptr);
  138.     auto tm = *std::localtime(&t);
  139.     std::ostringstream oss;
  140.     oss << std::put_time(&tm, "%d-%m-%Y-%H-%M-%S");
  141.     std::string filename = "log-" + oss.str() + ".svg";
  142.     for(std::uint32_t idx = 0; idx < log.size(); idx++){
  143.         float _start = 0;
  144.         for(const auto& res: log[idx]){
  145.             if (res.second == 0) continue;
  146.             const std::vector<float> x{_start, };
  147.             const std::vector<float> y{idx+1.f, idx+1.f};
  148.             line(_start,idx+1.f, _start + static_cast<float>(res.second)/1000.f, idx+1.f)->color(get_color(res.first)).line_width(2);
  149.             _start += static_cast<float>(res.second)/1000.f;
  150.         }
  151.     }
  152.     save(filename);
  153.     return 0;
  154. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement