diff options
author | Sven Gothel <[email protected]> | 2021-11-16 06:26:56 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2021-11-16 06:26:56 +0100 |
commit | eb8f5a8f2139f624f5817828ab6e6d9b2e8e9c73 (patch) | |
tree | 2cf60d73c7d27b30dd1e27e2924a9aba1bc86db1 /include | |
parent | 05c86d6dd0dbdf187cf40eefd26454a681fb6d73 (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.hpp | 112 |
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_ */ |