userver: userver/utils/atomic.hpp Source File
⚠️ This is the documentation for an old userver version. Click here to switch to the latest version.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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