Skip to content

Commit 73c24a3

Browse files
committed
Atomic: allow changing the default of std::memory_order_seq_cst
1 parent e50eb52 commit 73c24a3

File tree

1 file changed

+115
-1
lines changed

1 file changed

+115
-1
lines changed

lib/base/atomic.hpp

Lines changed: 115 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@ namespace icinga
1919
* initialization by std::atomic_init, see LWG issue 2334."
2020
* -- https://en.cppreference.com/w/cpp/atomic/atomic/atomic
2121
*
22+
* Also, the second template parameter allows to specify the default memory order once for all operations.
23+
*
2224
* @ingroup base
2325
*/
24-
template<class T>
26+
template<class T, std::memory_order m = std::memory_order_seq_cst>
2527
class Atomic : public std::atomic<T> {
2628
public:
2729
/**
@@ -32,6 +34,118 @@ class Atomic : public std::atomic<T> {
3234
inline Atomic(T desired) : std::atomic<T>(desired)
3335
{
3436
}
37+
38+
// The following methods have an argument with a default of std::memory_order_seq_cst hardcoded in the base class.
39+
// Hence, we need to override them here to allow for a different default memory order.
40+
41+
void store(T desired, std::memory_order mo = m) noexcept
42+
{
43+
std::atomic<T>::store(desired, mo);
44+
}
45+
46+
T load(std::memory_order mo = m) const noexcept
47+
{
48+
return std::atomic<T>::load(mo);
49+
}
50+
51+
T exchange(T desired, std::memory_order mo = m) noexcept
52+
{
53+
return std::atomic<T>::exchange(desired, mo);
54+
}
55+
56+
bool compare_exchange_weak(T& expected, T desired, std::memory_order mo = m) noexcept
57+
{
58+
return std::atomic<T>::compare_exchange_weak(expected, desired, mo);
59+
}
60+
61+
bool compare_exchange_strong(T& expected, T desired, std::memory_order mo = m) noexcept
62+
{
63+
return std::atomic<T>::compare_exchange_strong(expected, desired, mo);
64+
}
65+
66+
T fetch_add(T delta, std::memory_order mo = m) noexcept
67+
{
68+
return std::atomic<T>::fetch_add(delta, mo);
69+
}
70+
71+
T fetch_sub(T delta, std::memory_order mo = m) noexcept
72+
{
73+
return std::atomic<T>::fetch_sub(delta, mo);
74+
}
75+
76+
T fetch_and(T mask, std::memory_order mo = m) noexcept
77+
{
78+
return std::atomic<T>::fetch_and(mask, mo);
79+
}
80+
81+
T fetch_or(T mask, std::memory_order mo = m) noexcept
82+
{
83+
return std::atomic<T>::fetch_or(mask, mo);
84+
}
85+
86+
T fetch_xor(T mask, std::memory_order mo = m) noexcept
87+
{
88+
return std::atomic<T>::fetch_xor(mask, mo);
89+
}
90+
91+
// The following operators call non-virtual methods we have overridden above.
92+
// Hence, we need to override them here as well to allow for a different default memory order.
93+
94+
T operator=(T desired) noexcept
95+
{
96+
store(desired);
97+
return desired;
98+
}
99+
100+
operator T() const noexcept
101+
{
102+
return load();
103+
}
104+
105+
T operator+=(T delta) noexcept
106+
{
107+
return fetch_add(delta) + delta;
108+
}
109+
110+
T operator-=(T delta) noexcept
111+
{
112+
return fetch_sub(delta) - delta;
113+
}
114+
115+
T operator++() noexcept
116+
{
117+
return *this += 1;
118+
}
119+
120+
T operator++(int) noexcept
121+
{
122+
return fetch_add(1);
123+
}
124+
125+
T operator--() noexcept
126+
{
127+
return *this -= 1;
128+
}
129+
130+
T operator--(int) noexcept
131+
{
132+
return fetch_sub(1);
133+
}
134+
135+
T operator&=(T mask) noexcept
136+
{
137+
return fetch_and(mask) & mask;
138+
}
139+
140+
T operator|=(T mask) noexcept
141+
{
142+
return fetch_or(mask) | mask;
143+
}
144+
145+
T operator^=(T mask) noexcept
146+
{
147+
return fetch_xor(mask) ^ mask;
148+
}
35149
};
36150

37151
/**

0 commit comments

Comments
 (0)