userver: userver/utils/atomic.hpp Source File
Loading...
Searching...
No Matches
atomic.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/utils/atomic.hpp
4/// @brief Helper algorithms to work with atomics
5/// @ingroup userver_universal userver_concurrency
6
7#include <atomic>
8
9USERVER_NAMESPACE_BEGIN
10
11namespace utils {
12
13/// @ingroup userver_concurrency
14///
15/// @brief Atomically performs the operation of `updater` on `atomic`
16/// @details `updater` may be called multiple times per one call of
17/// `AtomicUpdate`, so it must be idempotent. To ensure that the function does
18/// not spin for a long time, `updater` must be fairly simple and fast.
19/// @param atomic the variable to update
20/// @param updater a lambda that takes the old value and produces the new value
21/// @return The updated value
22/// @note Uses std::memory_order_relaxed
23template <typename T, typename Func>
24T AtomicUpdate(std::atomic<T>& atomic, Func updater) {
25 T old_value = atomic.load();
26 while (true) {
27 // make a copy to to keep old_value unchanged
28 const T new_value = updater(T{old_value});
29
30 // don't mark cache line as dirty
31 if (old_value == new_value) return old_value;
32
33 if (atomic.compare_exchange_weak(old_value, new_value)) return new_value;
34 }
35}
36
37/// @ingroup userver_concurrency
38///
39/// @brief Concurrently safe sets `atomic` to a `value` if `value` is less
40///
41/// @note Uses std::memory_order_relaxed
42template <typename T>
43T AtomicMin(std::atomic<T>& atomic, T value) {
44 return utils::AtomicUpdate(atomic, [value](T old_value) { return value < old_value ? value : old_value; });
45}
46
47/// @ingroup userver_concurrency
48///
49/// @brief Concurrently safe sets `atomic` to a `value` if `value` is greater
50///
51/// @note Uses std::memory_order_relaxed
52template <typename T>
53T AtomicMax(std::atomic<T>& atomic, T value) {
54 return utils::AtomicUpdate(atomic, [value](T old_value) { return old_value < value ? value : old_value; });
55}
56
57} // namespace utils
58
59USERVER_NAMESPACE_END