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