From 14c6648c71b4b8a12ac0905ff23fcd4de7f0556f Mon Sep 17 00:00:00 2001 From: Oliver Reiche Date: Mon, 13 Jun 2022 13:30:13 +0200 Subject: multithreading: Add AtomicValue to atomically set/get value ... and use it to replace the commonly used pattern in Expression, LinkedMap, and GitTreeEntry. Furthermore, remove assignment operators for Expression and LinkedMap as those are considered to be used in an immutable manner anyway. --- src/buildtool/multithreading/TARGETS | 7 ++++ src/buildtool/multithreading/atomic_value.hpp | 54 +++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 src/buildtool/multithreading/atomic_value.hpp (limited to 'src/buildtool/multithreading') diff --git a/src/buildtool/multithreading/TARGETS b/src/buildtool/multithreading/TARGETS index 88bed701..c1545f0f 100644 --- a/src/buildtool/multithreading/TARGETS +++ b/src/buildtool/multithreading/TARGETS @@ -52,4 +52,11 @@ ] , "stage": ["src", "buildtool", "multithreading"] } +, "atomic_value": + { "type": ["@", "rules", "CC", "library"] + , "name": ["atomic_value"] + , "hdrs": ["atomic_value.hpp"] + , "deps": [["src/utils/cpp", "atomic"]] + , "stage": ["src", "buildtool", "multithreading"] + } } diff --git a/src/buildtool/multithreading/atomic_value.hpp b/src/buildtool/multithreading/atomic_value.hpp new file mode 100644 index 00000000..2c108a96 --- /dev/null +++ b/src/buildtool/multithreading/atomic_value.hpp @@ -0,0 +1,54 @@ +#ifndef INCLUDED_SRC_BUILDTOOL_MULTITHREADING_ATOMIC_VALUE_HPP +#define INCLUDED_SRC_BUILDTOOL_MULTITHREADING_ATOMIC_VALUE_HPP + +#include +#include +#include + +#include "src/utils/cpp/atomic.hpp" + +// Value that can be set and get atomically. Reset is not thread-safe. +template +class AtomicValue { + public: + AtomicValue() noexcept = default; + AtomicValue(AtomicValue const& other) noexcept + : data_{other.data_.load()} {} + AtomicValue(AtomicValue&& other) noexcept : data_{other.data_.load()} {} + ~AtomicValue() noexcept = default; + + auto operator=(AtomicValue const& other) noexcept = delete; + auto operator=(AtomicValue&& other) noexcept = delete; + + // Atomically set value once and return its reference. If this method is + // called multiple times concurrently, the setter is called only once. In + // any case, this method blocks until the value is ready. + [[nodiscard]] auto SetOnceAndGet( + std::function const& setter) const& noexcept -> T const& { + if (data_.load() == nullptr) { + if (not load_.exchange(true)) { + data_.store(std::make_shared(setter())); + data_.notify_all(); + } + else { + data_.wait(nullptr); + } + } + return *data_.load(); + } + + [[nodiscard]] auto SetOnceAndGet(std::function const& setter) && = + delete; + + // Reset, not thread-safe! + void Reset() noexcept { + load_ = false; + data_ = nullptr; + } + + private: + mutable std::atomic load_{false}; + mutable atomic_shared_ptr data_{nullptr}; +}; + +#endif // INCLUDED_SRC_BUILDTOOL_MULTITHREADING_ATOMIC_VALUE_HPP -- cgit v1.2.3