Guest User

Dining Philosophers Rebooted (VS2013)

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