diff options
author | Oliver Reiche <oliver.reiche@huawei.com> | 2022-06-13 13:30:13 +0200 |
---|---|---|
committer | Oliver Reiche <oliver.reiche@huawei.com> | 2022-06-13 15:39:47 +0200 |
commit | 14c6648c71b4b8a12ac0905ff23fcd4de7f0556f (patch) | |
tree | 265b9b616486e77ad69820d1fe5fc7feb088bb97 /src/buildtool/multithreading | |
parent | 1ad1906f2ac3f73ccf2283e4c1cc992557d91161 (diff) | |
download | justbuild-14c6648c71b4b8a12ac0905ff23fcd4de7f0556f.tar.gz |
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.
Diffstat (limited to 'src/buildtool/multithreading')
-rw-r--r-- | src/buildtool/multithreading/TARGETS | 7 | ||||
-rw-r--r-- | src/buildtool/multithreading/atomic_value.hpp | 54 |
2 files changed, 61 insertions, 0 deletions
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 <atomic> +#include <functional> +#include <optional> + +#include "src/utils/cpp/atomic.hpp" + +// Value that can be set and get atomically. Reset is not thread-safe. +template <class T> +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<T()> const& setter) const& noexcept -> T const& { + if (data_.load() == nullptr) { + if (not load_.exchange(true)) { + data_.store(std::make_shared<T>(setter())); + data_.notify_all(); + } + else { + data_.wait(nullptr); + } + } + return *data_.load(); + } + + [[nodiscard]] auto SetOnceAndGet(std::function<T()> const& setter) && = + delete; + + // Reset, not thread-safe! + void Reset() noexcept { + load_ = false; + data_ = nullptr; + } + + private: + mutable std::atomic<bool> load_{false}; + mutable atomic_shared_ptr<T> data_{nullptr}; +}; + +#endif // INCLUDED_SRC_BUILDTOOL_MULTITHREADING_ATOMIC_VALUE_HPP |