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 | } |