diff options
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | latch.h | 41 | ||||
-rw-r--r-- | test/latch.cc | 37 |
3 files changed, 79 insertions, 0 deletions
@@ -3,6 +3,7 @@ TEST += option TEST += timer TEST += log TEST += owning_mutex +TEST += latch # -- INTERNALS ----------------------------------------------------------------- @@ -0,0 +1,41 @@ +#ifndef UTILS_TIMER_H +#define UTILS_TIMER_H + +#include <condition_variable> +#include <mutex> + +#include <cassert> + +/// latch +/// +/// A simple one-shot latch based on a mutex and condition variable. +/// +/// The latch is initialized with a number N of threads to wait for. Different +/// threads can call arrive_and_wait() on the latch. Those threads enter a wait +/// state until the Nth thread calls arrive_and_wait(), which then releases all +/// threads at the same time. +struct latch { + explicit latch(std::size_t cnt) : m_cnt{cnt} {} + ~latch() { + assert(m_cnt == 0); + } + + void arrive_and_wait() { + std::unique_lock<std::mutex> lk(m_mtx); + m_cnt -= 1; + + if (m_cnt != 0) { + m_cv.wait(lk, [this]() { return m_cnt == 0; }); + } else { + m_cv.notify_all(); + } + } + + private: + std::size_t m_cnt; + + std::mutex m_mtx; + std::condition_variable m_cv; +}; + +#endif diff --git a/test/latch.cc b/test/latch.cc new file mode 100644 index 0000000..567e3db --- /dev/null +++ b/test/latch.cc @@ -0,0 +1,37 @@ +#include <latch.h> + +#include <chrono> +#include <thread> +#include <vector> + +#include <cassert> +#include <cstdio> + +constexpr unsigned kNumThreads = 16; + +int main() { + latch gate(kNumThreads); + + std::vector<std::thread> threads; + threads.reserve(kNumThreads); + + for (unsigned t = 0; t < kNumThreads; ++t) { + threads.emplace_back([&gate, t]() { + if (t % 2 == 0) { + unsigned sec = t / 2; + std::printf("th%02u sleep %us\n", t, sec); + std::this_thread::sleep_for(std::chrono::seconds(sec)); + } + + std::printf("th%02u at gate\n", t); + gate.arrive_and_wait(); + std::printf("th%02u finished\n", t); + }); + } + + for (auto& th : threads) { + th.join(); + } + + return 0; +} |