Guest User

Dining Philosophers Rebooted (VS2013)

a guest
Sep 20th, 2014
310
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #include <chrono>
  2. #include <mutex>
  3. #include <random>
  4. #include <array>
  5. #include <vector>
  6. #include <thread>
  7. #include <iostream>
  8.  
  9. #ifdef SMART_POLITE
  10.  
  11. template <class L0, class L1> void lock(L0 &l0, L1 &l1) {
  12.   while (true) {
  13.     {
  14.       std::unique_lock<L0> u0(l0);
  15.       if (l1.try_lock()) {
  16.         u0.release();
  17.         break;
  18.       }
  19.     }
  20.     std::this_thread::yield();
  21.     {
  22.       std::unique_lock<L1> u1(l1);
  23.       if (l0.try_lock()) {
  24.         u1.release();
  25.         break;
  26.       }
  27.     }
  28.     std::this_thread::yield();
  29.   }
  30. }
  31.  
  32. #elif defined(SMART)
  33.  
  34. template <class L0, class L1> void lock(L0 &l0, L1 &l1) {
  35.   while (true) {
  36.     {
  37.       std::unique_lock<L0> u0(l0);
  38.       if (l1.try_lock()) {
  39.         u0.release();
  40.         break;
  41.       }
  42.     }
  43.     {
  44.       std::unique_lock<L1> u1(l1);
  45.       if (l0.try_lock()) {
  46.         u1.release();
  47.         break;
  48.       }
  49.     }
  50.   }
  51. }
  52.  
  53. #elif defined(PERSISTENT)
  54.  
  55. template <class L0, class L1> void lock(L0 &l0, L1 &l1) {
  56.   while (true) {
  57.     std::unique_lock<L0> u0(l0);
  58.     if (l1.try_lock()) {
  59.       u0.release();
  60.       break;
  61.     }
  62.   }
  63. }
  64.  
  65. #elif defined(ORDERED)
  66.  
  67. template <class L0> void lock(L0 &l0, L0 &l1) {
  68.   if (l0.mutex() < l1.mutex()) {
  69.     std::unique_lock<L0> u0(l0);
  70.     l1.lock();
  71.     u0.release();
  72.   } else {
  73.     std::unique_lock<L0> u1(l1);
  74.     l0.lock();
  75.     u1.release();
  76.   }
  77. }
  78.  
  79. #elif defined(STD)
  80.  
  81. template <class L0> void lock(L0 &l0, L0 &l1) { std::lock(l0, l1); }
  82.  
  83. #endif
  84.  
  85. #define constexpr const
  86.  
  87. class Philosopher {
  88.   std::mt19937_64 eng_{std::random_device{}()};
  89.  
  90.   std::mutex &left_fork_;
  91.   std::mutex &right_fork_;
  92.   std::chrono::milliseconds eat_time_{0};
  93.   static constexpr std::chrono::seconds full_;
  94.  
  95. public:
  96.   Philosopher(std::mutex &left, std::mutex &right);
  97.   void dine();
  98.  
  99. private:
  100.   void eat();
  101.   bool flip_coin();
  102.   std::chrono::milliseconds get_eat_duration();
  103. };
  104.  
  105. constexpr std::chrono::seconds Philosopher::full_{30};
  106.  
  107. Philosopher::Philosopher(std::mutex &left, std::mutex &right)
  108.     : left_fork_(left), right_fork_(right) {}
  109.  
  110. void Philosopher::dine() {
  111.   while (eat_time_ < full_)
  112.     eat();
  113. }
  114.  
  115. void Philosopher::eat() {
  116.   using Lock = std::unique_lock<std::mutex>;
  117.   Lock first;
  118.   Lock second;
  119.   if (flip_coin()) {
  120.     first = Lock(left_fork_, std::defer_lock);
  121.     second = Lock(right_fork_, std::defer_lock);
  122.   } else {
  123.     first = Lock(right_fork_, std::defer_lock);
  124.     second = Lock(left_fork_, std::defer_lock);
  125.   }
  126.   auto d = get_eat_duration();
  127.   ::lock(first, second);
  128.   auto end = std::chrono::steady_clock::now() + d;
  129.   while (std::chrono::steady_clock::now() < end)
  130.     ;
  131.   eat_time_ += d;
  132. }
  133.  
  134. bool Philosopher::flip_coin() {
  135.   std::bernoulli_distribution d;
  136.   return d(eng_);
  137. }
  138.  
  139. std::chrono::milliseconds Philosopher::get_eat_duration() {
  140.   std::uniform_int_distribution<> ms(1, 10);
  141.   return std::min(std::chrono::milliseconds(ms(eng_)), full_ - eat_time_);
  142. }
  143.  
  144. int main() {
  145. #ifdef SMART_POLITE
  146.   std::cout << "SMART_POLITE\n";
  147. #elif defined(SMART)
  148.   std::cout << "SMART\n";
  149. #elif defined(PERSISTENT)
  150.   std::cout << "PERSISTENT\n";
  151. #elif defined(ORDERED)
  152.   std::cout << "ORDERED\n";
  153. #elif defined(STD)
  154.   std::cout << "STANDARD\n";
  155. #endif
  156.   for (unsigned nt = 2; nt <= 32; ++nt) {
  157.     std::vector<std::mutex> table(nt);
  158.     std::vector<Philosopher> diners;
  159.     for (unsigned i = 0; i < table.size(); ++i) {
  160.       int j = i;
  161.       int k = j < table.size() - 1 ? j + 1 : 0;
  162.       diners.push_back(Philosopher(table[j], table[k]));
  163.     }
  164.     std::vector<std::thread> threads(diners.size());
  165.     unsigned i = 0;
  166.     auto t0 = std::chrono::high_resolution_clock::now();
  167.     for (auto &t : threads) {
  168.       t = std::thread(&Philosopher::dine, diners[i]);
  169.       ++i;
  170.     }
  171.     for (auto &t : threads)
  172.       t.join();
  173.     auto t1 = std::chrono::high_resolution_clock::now();
  174.     using secs = std::chrono::duration<float>;
  175.     std::cout << "nt = " << nt << " : " << secs(t1 - t0).count() << std::endl;
  176.   }
  177. }
Advertisement
Add Comment
Please, Sign In to add comment