diff options
Diffstat (limited to 'src/common/thread.h')
| -rw-r--r-- | src/common/thread.h | 46 |
1 files changed, 22 insertions, 24 deletions
diff --git a/src/common/thread.h b/src/common/thread.h index 8255ee6d3..bbfa8befa 100644 --- a/src/common/thread.h +++ b/src/common/thread.h | |||
| @@ -30,8 +30,7 @@ | |||
| 30 | # endif | 30 | # endif |
| 31 | #endif | 31 | #endif |
| 32 | 32 | ||
| 33 | namespace Common | 33 | namespace Common { |
| 34 | { | ||
| 35 | 34 | ||
| 36 | int CurrentThreadId(); | 35 | int CurrentThreadId(); |
| 37 | 36 | ||
| @@ -43,55 +42,55 @@ public: | |||
| 43 | Event() : is_set(false) {} | 42 | Event() : is_set(false) {} |
| 44 | 43 | ||
| 45 | void Set() { | 44 | void Set() { |
| 46 | std::lock_guard<std::mutex> lk(m_mutex); | 45 | std::lock_guard<std::mutex> lk(mutex); |
| 47 | if (!is_set) { | 46 | if (!is_set) { |
| 48 | is_set = true; | 47 | is_set = true; |
| 49 | m_condvar.notify_one(); | 48 | condvar.notify_one(); |
| 50 | } | 49 | } |
| 51 | } | 50 | } |
| 52 | 51 | ||
| 53 | void Wait() { | 52 | void Wait() { |
| 54 | std::unique_lock<std::mutex> lk(m_mutex); | 53 | std::unique_lock<std::mutex> lk(mutex); |
| 55 | m_condvar.wait(lk, [&]{ return is_set; }); | 54 | condvar.wait(lk, [&]{ return is_set; }); |
| 56 | is_set = false; | 55 | is_set = false; |
| 57 | } | 56 | } |
| 58 | 57 | ||
| 59 | void Reset() { | 58 | void Reset() { |
| 60 | std::unique_lock<std::mutex> lk(m_mutex); | 59 | std::unique_lock<std::mutex> lk(mutex); |
| 61 | // no other action required, since wait loops on the predicate and any lingering signal will get cleared on the first iteration | 60 | // no other action required, since wait loops on the predicate and any lingering signal will get cleared on the first iteration |
| 62 | is_set = false; | 61 | is_set = false; |
| 63 | } | 62 | } |
| 64 | 63 | ||
| 65 | private: | 64 | private: |
| 66 | bool is_set; | 65 | bool is_set; |
| 67 | std::condition_variable m_condvar; | 66 | std::condition_variable condvar; |
| 68 | std::mutex m_mutex; | 67 | std::mutex mutex; |
| 69 | }; | 68 | }; |
| 70 | 69 | ||
| 71 | class Barrier { | 70 | class Barrier { |
| 72 | public: | 71 | public: |
| 73 | Barrier(size_t count) : m_count(count), m_waiting(0) {} | 72 | explicit Barrier(size_t count_) : count(count_), waiting(0), generation(0) {} |
| 74 | 73 | ||
| 75 | /// Blocks until all "count" threads have called Sync() | 74 | /// Blocks until all "count" threads have called Sync() |
| 76 | void Sync() { | 75 | void Sync() { |
| 77 | std::unique_lock<std::mutex> lk(m_mutex); | 76 | std::unique_lock<std::mutex> lk(mutex); |
| 77 | const size_t current_generation = generation; | ||
| 78 | 78 | ||
| 79 | // TODO: broken when next round of Sync()s | 79 | if (++waiting == count) { |
| 80 | // is entered before all waiting threads return from the notify_all | 80 | generation++; |
| 81 | 81 | waiting = 0; | |
| 82 | if (++m_waiting == m_count) { | 82 | condvar.notify_all(); |
| 83 | m_waiting = 0; | ||
| 84 | m_condvar.notify_all(); | ||
| 85 | } else { | 83 | } else { |
| 86 | m_condvar.wait(lk, [&]{ return m_waiting == 0; }); | 84 | condvar.wait(lk, [this, current_generation]{ return current_generation != generation; }); |
| 87 | } | 85 | } |
| 88 | } | 86 | } |
| 89 | 87 | ||
| 90 | private: | 88 | private: |
| 91 | std::condition_variable m_condvar; | 89 | std::condition_variable condvar; |
| 92 | std::mutex m_mutex; | 90 | std::mutex mutex; |
| 93 | const size_t m_count; | 91 | const size_t count; |
| 94 | size_t m_waiting; | 92 | size_t waiting; |
| 93 | size_t generation; // Incremented once each time the barrier is used | ||
| 95 | }; | 94 | }; |
| 96 | 95 | ||
| 97 | void SleepCurrentThread(int ms); | 96 | void SleepCurrentThread(int ms); |
| @@ -100,8 +99,7 @@ void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms | |||
| 100 | // Use this function during a spin-wait to make the current thread | 99 | // Use this function during a spin-wait to make the current thread |
| 101 | // relax while another thread is working. This may be more efficient | 100 | // relax while another thread is working. This may be more efficient |
| 102 | // than using events because event functions use kernel calls. | 101 | // than using events because event functions use kernel calls. |
| 103 | inline void YieldCPU() | 102 | inline void YieldCPU() { |
| 104 | { | ||
| 105 | std::this_thread::yield(); | 103 | std::this_thread::yield(); |
| 106 | } | 104 | } |
| 107 | 105 | ||