userver
C++ Async Framework
Toggle main menu visibility
Loading...
Searching...
No Matches
striped_counter.hpp
Go to the documentation of this file.
1
#
pragma
once
2
3
/// @file userver/concurrent/striped_counter.hpp
4
/// @brief @copybrief concurrent::StripedCounter
5
6
#
include
<
cstdint
>
7
8
#
include
<
userver
/
utils
/
fast_pimpl
.
hpp
>
9
10
USERVER_NAMESPACE_BEGIN
11
12
namespace
concurrent
{
13
14
/// @ingroup userver_concurrency
15
///
16
/// @brief A contention-free sharded atomic counter, with memory consumption
17
/// and read performance traded for write performance. Intended to be used for
18
/// write-heavy counters, mostly in metrics.
19
///
20
/// @note Depending on the underlying platform is implemented either via a
21
/// single atomic variable, or an 'nproc'-sized array of interference-shielded
22
/// rseq-based (https://www.phoronix.com/news/Restartable-Sequences-Speed)
23
/// per-CPU counters.
24
/// In the second case, read is approx. `nproc` times slower than write.
25
class
StripedCounter
final
{
26
public
:
27
/// @brief Constructs a zero-initialized counter.
28
/// Might allocate up to kDestructiveInterferenceSize (64 bytes for x86_64) *
29
/// number of available CPUs bytes.
30
StripedCounter
();
31
~StripedCounter();
32
33
StripedCounter(
const
StripedCounter&) =
delete
;
34
StripedCounter& operator=(
const
StripedCounter&) =
delete
;
35
36
StripedCounter(StripedCounter&&) =
delete
;
37
StripedCounter& operator=(StripedCounter&&) =
delete
;
38
39
/// @brief The addition is done with a relaxed memory order.
40
void
Add
(std::uintptr_t value)
noexcept
;
41
42
/// @brief The subtraction is done with a relaxed memory order.
43
void
Subtract
(std::uintptr_t value)
noexcept
{
44
// Perfectly defined unsigned wrapping
45
Add
(
-value
)
;
46
}
47
48
/// @brief Read the total counter value. The counter uses the full range
49
/// of `std::uintptr_t`, using wrap-around when necessary.
50
/// @note The read is done with `std::memory_order_acquire`.
51
///
52
/// Due to the underlying implementation being an array of counters, this
53
/// function may return logically impossible values if `Subtract` is in play.
54
/// For example, doing `Add(1)`, then `Subtract(1)` in one thread and `Read` in another thread in parallel
55
/// may lead to this function returning -1 (wrapped).
56
/// With `Subtract`, consider using `NonNegativeRead` instead.
57
std::
uintptr_t
Read
()
const
noexcept
;
58
59
/// @brief Read the non-negative total counter value.
60
/// @note The read is done with `std::memory_order_acquire`.
61
///
62
/// This is almost exactly like `Read`, but for an `Add-Subtract` race,
63
/// instead of returning a negative value, this function returns `0`. Consider
64
/// this a convenient shortcut to avoid seeing logically impossible negative
65
/// values.
66
std::
uintptr_t
NonNegativeRead
()
const
noexcept
;
67
68
private
:
69
struct
Impl;
70
utils
::FastPimpl<Impl, 32, 8> impl_;
71
};
72
73
}
// namespace concurrent
74
75
USERVER_NAMESPACE_END
userver
concurrent
striped_counter.hpp
Generated on
for userver by
Doxygen
1.17.0