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
6#include <atomic>
7
8USERVER_NAMESPACE_BEGIN
9
10namespace utils {
11
12/// @ingroup userver_universal userver_concurrency
13///
14/// @brief Atomically performs the operation of `updater` on `atomic`
15/// @details `updater` may be called multiple times per one call of
16/// `AtomicUpdate`, so it must be idempotent. To ensure that the function does
17/// not spin for a long time, `updater` must be fairly simple and fast.
18/// @param atomic the variable to update
19/// @param updater a lambda that takes the old value and produces the new value
20/// @return The updated value
21template <typename T, typename Func>
22T AtomicUpdate(std::atomic<T>& atomic, Func updater) {
23 T old_value = atomic.load();
24 while (true) {
25 // make a copy to to keep old_value unchanged
26 const T new_value = updater(T{old_value});
27 if (atomic.compare_exchange_weak(old_value, new_value)) return new_value;
28 }
29}
30
31/// @ingroup userver_universal userver_concurrency
32///
33/// @brief Concurrently safe sets `atomic` to a `value` if `value` is less
34template <typename T>
35T AtomicMin(std::atomic<T>& atomic, T value) {
36 return utils::AtomicUpdate(atomic, [value](T old_value) {
37 return value < old_value ? value : old_value;
38 });
39}
40
41/// @ingroup userver_universal userver_concurrency
42///
43/// @brief Concurrently safe sets `atomic` to a `value` if `value` is greater
44template <typename T>
45T AtomicMax(std::atomic<T>& atomic, T value) {
46 return utils::AtomicUpdate(atomic, [value](T old_value) {
47 return old_value < value ? value : old_value;
48 });
49}
50
51} // namespace utils
52
53USERVER_NAMESPACE_END