Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <chrono>
- #include <mutex>
- #include <random>
- #include <array>
- #include <vector>
- #include <thread>
- #include <iostream>
- #ifdef SMART_POLITE
- template <class L0, class L1>
- void
- lock(L0& l0, L1& l1)
- {
- while (true)
- {
- {
- std::unique_lock<L0> u0(l0);
- if (l1.try_lock())
- {
- u0.release();
- break;
- }
- }
- std::this_thread::yield();
- {
- std::unique_lock<L1> u1(l1);
- if (l0.try_lock())
- {
- u1.release();
- break;
- }
- }
- std::this_thread::yield();
- }
- }
- #elif defined(SMART)
- template <class L0, class L1>
- void
- lock(L0& l0, L1& l1)
- {
- while (true)
- {
- {
- std::unique_lock<L0> u0(l0);
- if (l1.try_lock())
- {
- u0.release();
- break;
- }
- }
- {
- std::unique_lock<L1> u1(l1);
- if (l0.try_lock())
- {
- u1.release();
- break;
- }
- }
- }
- }
- #elif defined(PERSISTENT)
- template <class L0, class L1>
- void
- lock(L0& l0, L1& l1)
- {
- while (true)
- {
- std::unique_lock<L0> u0(l0);
- if (l1.try_lock())
- {
- u0.release();
- break;
- }
- }
- }
- #elif defined(ORDERED)
- template <class L0>
- void
- lock(L0& l0, L0& l1)
- {
- if (l0.mutex() < l1.mutex())
- {
- std::unique_lock<L0> u0(l0);
- l1.lock();
- u0.release();
- }
- else
- {
- std::unique_lock<L0> u1(l1);
- l0.lock();
- u1.release();
- }
- }
- #elif defined(STD)
- template <class L0>
- void
- lock(L0& l0, L0& l1)
- {
- std::lock(l0, l1);
- }
- #endif
- #define constexpr const
- class Philosopher
- {
- std::mt19937_64 eng_{ std::random_device{}() };
- std::mutex& left_fork_;
- std::mutex& right_fork_;
- std::chrono::milliseconds eat_time_{ 0 };
- static constexpr std::chrono::seconds full_;
- public:
- Philosopher(std::mutex& left, std::mutex& right);
- void dine();
- private:
- void eat();
- bool flip_coin();
- std::chrono::milliseconds get_eat_duration();
- };
- constexpr std::chrono::seconds Philosopher::full_{ 30 };
- Philosopher::Philosopher(std::mutex& left, std::mutex& right)
- : left_fork_(left)
- , right_fork_(right)
- {}
- void
- Philosopher::dine()
- {
- while (eat_time_ < full_)
- eat();
- }
- void
- Philosopher::eat()
- {
- using Lock = std::unique_lock<std::mutex>;
- Lock first;
- Lock second;
- if (flip_coin())
- {
- first = Lock(left_fork_, std::defer_lock);
- second = Lock(right_fork_, std::defer_lock);
- }
- else
- {
- first = Lock(right_fork_, std::defer_lock);
- second = Lock(left_fork_, std::defer_lock);
- }
- auto d = get_eat_duration();
- ::lock(first, second);
- auto end = std::chrono::steady_clock::now() + d;
- while (std::chrono::steady_clock::now() < end)
- ;
- eat_time_ += d;
- }
- bool
- Philosopher::flip_coin()
- {
- std::bernoulli_distribution d;
- return d(eng_);
- }
- std::chrono::milliseconds
- Philosopher::get_eat_duration()
- {
- std::uniform_int_distribution<> ms(1, 10);
- return std::min(std::chrono::milliseconds(ms(eng_)), full_ - eat_time_);
- }
- int
- main()
- {
- #ifdef SMART_POLITE
- std::cout << "SMART_POLITE\n";
- #elif defined(SMART)
- std::cout << "SMART\n";
- #elif defined(PERSISTENT)
- std::cout << "PERSISTENT\n";
- #elif defined(ORDERED)
- std::cout << "ORDERED\n";
- #elif defined(STD)
- std::cout << "STANDARD\n";
- #endif
- for (unsigned nt = 2; nt <= 32; ++nt)
- {
- std::vector<std::mutex> table(nt);
- std::vector<Philosopher> diners;
- for (unsigned i = 0; i < table.size(); ++i)
- {
- int j = i;
- int k = j < table.size() - 1 ? j + 1 : 0;
- diners.push_back(Philosopher(table[j], table[k]));
- }
- std::vector<std::thread> threads(diners.size());
- unsigned i = 0;
- auto t0 = std::chrono::high_resolution_clock::now();
- for (auto& t : threads)
- {
- t = std::thread(&Philosopher::dine, diners[i]);
- ++i;
- }
- for (auto& t : threads)
- t.join();
- auto t1 = std::chrono::high_resolution_clock::now();
- using secs = std::chrono::duration<float>;
- std::cout << "nt = " << nt << " : " << secs(t1 - t0).count() << std::endl;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment