aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2021-11-16 06:26:56 +0100
committerSven Gothel <[email protected]>2021-11-16 06:26:56 +0100
commiteb8f5a8f2139f624f5817828ab6e6d9b2e8e9c73 (patch)
tree2cf60d73c7d27b30dd1e27e2924a9aba1bc86db1 /include
parent05c86d6dd0dbdf187cf40eefd26454a681fb6d73 (diff)
Add jau::latch implementation for C++17, inspired by std::latch C++20
This latch implementation uses a size_t counter, exceeding std::latch ptrdiff_t. Since we use memory_order_seq_cst for the counter atomic, try_wait() shall always return the correct result.
Diffstat (limited to 'include')
-rw-r--r--include/jau/latch.hpp112
1 files changed, 112 insertions, 0 deletions
diff --git a/include/jau/latch.hpp b/include/jau/latch.hpp
new file mode 100644
index 0000000..3c0ad6e
--- /dev/null
+++ b/include/jau/latch.hpp
@@ -0,0 +1,112 @@
+/*
+ * Author: Sven Gothel <[email protected]>
+ * Copyright (c) 2021 Gothel Software e.K.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef JAU_LATCH_HPP_
+#define JAU_LATCH_HPP_
+
+#include <cstdint>
+#include <mutex>
+#include <condition_variable>
+
+#include <jau/ordered_atomic.hpp>
+
+/**
+ * Inspired by std::latch of C++20
+ *
+ * @see https://en.cppreference.com/w/cpp/thread/latch
+ */
+class latch {
+ private:
+ std::mutex mtx_cd;
+ std::mutex mtx_cv;
+ std::condition_variable cv;
+ jau::sc_atomic_size_t count;
+
+ public:
+ /** Returns the maximum value of the internal counter supported by the implementation. */
+ static constexpr size_t max() noexcept { return std::numeric_limits<size_t>::max(); }
+
+ constexpr latch(const size_t count_) noexcept
+ : count(count_) {}
+
+ latch(const latch& o) = delete;
+
+ /**
+ * Atomically decrements the internal counter by n
+ * and notifies all blocked wait() threads if zero is reached.
+ *
+ * If n is greater than the value of the internal counter, the counter is set to zero.
+ *
+ * This operation strongly happens-before all calls that are unblocked on this latch.
+ *
+ * @param n the value by which the internal counter is decreased, defaults to 1
+ */
+ void count_down(const size_t n = 1) noexcept {
+ bool notify;
+ {
+ std::unique_lock<std::mutex> lock(mtx_cd); // Avoid data-race on concurrent count_down() calls
+ if( n < count ) {
+ count -= n;
+ notify = false;
+ } else {
+ count = 0;
+ notify = true;
+ }
+ }
+ if( notify ) {
+ cv.notify_all();
+ }
+ }
+
+ /**
+ * Returns true only if the internal counter has reached zero.
+ */
+ bool try_wait() const noexcept {
+ return 0 == count;
+ }
+
+ /**
+ * Blocks the calling thread until the internal counter reaches 0. If it is zero already, returns immediately.
+ */
+ void wait() const noexcept {
+ if( 0 < count ) {
+ std::unique_lock<std::mutex> lock(mtx_cv);
+ cv.wait(lock, [&count]{ return 0 == count; });
+ }
+ }
+
+ /**
+ * Atomically decrements the internal counter by n and (if necessary) blocks the calling thread until the counter reaches zero.
+ *
+ * Equivalent to count_down(n); wait();.
+ *
+ * @param n the value by which the internal counter is decreased, defaults to 1
+ */
+ void arrive_and_wait(const size_t n = 1) noexcept {
+ count_down(n);
+ wait();
+ }
+};
+
+#endif /* JAU_LATCH_HPP_ */