summaryrefslogtreecommitdiff
path: root/src/buildtool/multithreading
diff options
context:
space:
mode:
authorOliver Reiche <oliver.reiche@huawei.com>2022-06-13 13:30:13 +0200
committerOliver Reiche <oliver.reiche@huawei.com>2022-06-13 15:39:47 +0200
commit14c6648c71b4b8a12ac0905ff23fcd4de7f0556f (patch)
tree265b9b616486e77ad69820d1fe5fc7feb088bb97 /src/buildtool/multithreading
parent1ad1906f2ac3f73ccf2283e4c1cc992557d91161 (diff)
downloadjustbuild-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/TARGETS7
-rw-r--r--src/buildtool/multithreading/atomic_value.hpp54
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