File: atomic.yo

package info (click to toggle)
c%2B%2B-annotations 12.2.0-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 13,044 kB
  • sloc: cpp: 24,337; makefile: 1,517; ansic: 165; sh: 121; perl: 90
file content (259 lines) | stat: -rw-r--r-- 12,029 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
Before using the facilities introduced in this section the tthi(atomic) header
file must be included.

When data are shared among multiple threads, data corruption is usually
prevented using mutexes. To increment a simple tt(int) using this strategy
code as shown below is commonly used:
        verb(    {
        lock_guard<mutex> lk{ intVarMutex };
        ++intVar;
    })

The compound statement is used to limit the tt(lock_guard's) lifetime, so
that tt(intVar) is only locked for a short little while.

    This scheme is not complex, but at the end of the day having to define a
tt(lock_guard) for every single use of a simple variable, and having to define
a matching mutex for each simple variable is a bit annoying and cumbersome.

    bf(C++) offers a way out through the use of emi(atomic data types).
Atomic data types are available for all basic types, and also for (trivial)
user defined types. Trivial types are (see also section ref(TYPETRAITS)) all
scalar types, arrays of elements of a trivial type, and classes whose
constructors, copy constructors, and destructors all have default
implementations, and their non-static data members are themselves of trivial
types.

The class template hi(atomic<Type>)tt(std::atomic<Type>) is available for all
built-in types, including pointer types. E.g., tt(std::atomic<bool>) defines
an atomic tt(bool) type. For many types alternative somewhat shorter
type names are available. E.g, instead of tt(std::atomic<unsigned short>) the
type tt(std::atomic_ushort) can be used. Refer to the tt(atomic) header file
for a complete list of alternate names.

If tt(Trivial) is a user-defined trivial type then
        hi(atomic<Trivial>)tt(std::atomic<Trivial>)
defines an atomic variant of tt(Trivial): such a type does not require 
a separate tt(mutex) to synchronize access by multiple threads.

Objects of the class template tt(std::atomic<Type>) cannot directly be copied
or assigned to each other. However, they can be initialized by values of type
tt(Type), and values of type tt(Type) can also directly be assigned to
tt(std::atomic<Type>) objects. Moreover, since tt(atomic<Type>) types offer
conversion operators returning their tt(Type) values, an tt(atomic<Type>)
objects can also be assigned to or initialized by another tt(atomic<Type>)
object using a tt(static_cast):
        verb(    atomic<int> a1 = 5;
    atomic<int> a2{ static_cast<int>(a1) };)

The class tt(std::atomic<Type>) provides several public members, shown
below. Non-member (free) functions operating on tt(atomic<Type>) objects are
also available.


The tt(std::memory_order) enumeration defines the following symbolic
constants, which are used to specify ordering constraints of atomic operations:
    itemization(
    itt(memory_order_acq_rel:) the operation must be a read-modify-write
        operation, combining tt(memory_order_acquire) and
        tt(memory_order_release); 
    itt(memory_order_acquire:) the operation is an acquire operation. It
        synchronizes with a release operation that wrote the same memory
        location; 
    itt(memory_order_consume:) the operation is a consume operation on the
        involved memory location;
    itt(memory_order_relaxed:) no ordering constraints are provided by the
        operation;
    itt(memory_order_release:) the operation is a release operation. It
        synchronizes with acquire operations on the same location;
    itt(memory_order_sec_cst:) the default memory order specification for all
        operations. Memory storing operations use tt(memory_order_release),
        memory load operations use tt(memory_order_acquire), and
        read-modify-write operations use tt(memory_order_acq_rel).
    )

The memory order cannot be specified for the overloaded operators provided by
tt(atomic<Type>). Otherwise, most tt(atomic) member functions may also be
given a final tt(memory_order) argument. Where this is not available it is
explictly mentioned at the function's description.


Here are the standard available tt(std::atomic<Type>) member functions:
    itemization(
    ithtq(compare_exchange_strong)(bool compare_exchange_strong(Type
        &currentValue, Type newValue) noexcept)
       (The value in the atomic object is compared to tt(newValue) using
        byte-wise comparisons. If equal (and tt(true) is returned) then
        tt(newValue) is stored in the atomic object; if unequal (and tt(false)
        is returned) the object's current value is stored in
        tt(currentValue);)

    ithtq(compare_exchange_weak)(bool compare_exchange_weak(Type &oldValue,
        Type newValue) noexcept)
       (The value in the atomic object is compared to tt(newValue) using
        byte-wise comparisons. If equal (and tt(true) is returned),
        then tt(newValue) is stored in the atomic object; if unequal, or
        tt(newValue) cannot be atomically assigned to the current object
        tt(false) is returned and the object's current value is stored in
        tt(currentValue);)

    ithtq(exchange)(Type exchange(Type newValue) noexcept)
       (The object's current value is returned, and tt(newValue) is assigned
        to the current object;)

    ithtq(is_lock_free)(bool is_lock_free() const noexept)
       (If the operations on the current object can be performed lock-free
        tt(true) is returned, otherwise tt(false).
        This member has no tt(memory_order) parameter;)

    ithtq(load)(Type load() const noexcept)
       (The object's value is returned;)

    ittq(operator Type() const noexcept)
       (The object's value is returned;)

    ithtq(store)(void store(Type newValue) noexcept)
       (tt(NewValue) is assigned to the current object. Note that the standard
        assignment operator can also be used.)
    )
    
In addition to the above members, integral atomic types `tt(Integral)'
(essentially the atomic variants of all built-in integral types) also offer
the following member functions:
    itemization(
    ithtq(fetch_add)(Integral fetch_add(Integral value) noexcept)
       (tt(Value) is added to the object's value, and the object's
        value at the time of the call is returned;)

    ithtq(fetch_sub)(Integral fetch_sub(Integral value) noexcept)
       (tt(Value) is subtracted from the object's value, and the object's
        value at the time of the call is returned;)

    ithtq(fetch_and)(Integral fetch_and(Integral mask) noexcept)
       (The tt(bit-and) operator is applied to the object's value and
        tt(mask), assigning the resulting value to the current object. The
        object's value at the time of the call is returned;)

    ithtq(fetch_|=)(Integral fetch_|=(Integral mask) noexcept)
       (The tt(bit-or) operator is applied to the object's value and tt(mask),
        assigning the resulting value to the current object. The object's
        value at the time of the call is returned;)

    ithtq(fetch_^=)(Integral fetch_^=(Integral mask) noexcept)
       (The tt(bit-xor) operator is applied to the object's value and
        tt(mask), assigning the resulting value to the current object. The
        object's value at the time of the call is returned;)

    ithtq(operator++)(Integral operator++() noexcept)
       (The prefix increment operator, returning object's new value;)
    
    ithtq(operator++)(Integral operator++(int) noexcept)
       (The postfix increment operator, returning the object's value before it
        was incremented;)

    it()hi(operator--)ttNoCt(Integral operator--() noexcept)\
        quote(The prefix decrement operator, returning object's new value;)
    
    it()hi(operator--)ttNoCt(Integral operator--(int) noexcept)\
        quote(The postfix decrement operator, returning the object's value
            before it was decremented;)

    ithtq(operator+=)(Integral operator+=(Integral value) noexcept)
       (tt(Value) is added to the object's current value and the object's
        new value is returned;)

    ithtq(operator-=)(Integral operator-=(Integral value) noexcept)
       (tt(Value) is subtracted from the object's current value and the
        object's new value is returned;)

    ithtq(operator&=)(Integral operator&=(Integral mask) noexcept)
       (The tt(bit-and) operator is applied to the object's current value and
        tt(mask), assigning the resulting value to the current object. The
        object's new value is returned;)

    ithtq(operator|=)(Integral operator|=(Integral mask) noexcept)
       (The tt(bit-or) operator is applied to the object's current value and
        tt(mask), assigning the resulting value to the current object. The
        object's new value is returned;)

    ithtq(operator^=)(Integral operator^=(Integral mask) noexcept)
       (The tt(bit-xor) operator is applied to the object's current value and
        tt(mask), assigning the resulting value to the current object. The
        object's new value is returned;)
    )
    
Some of the free member functions have names ending in tt(_explicit). The
tt(_explicit) functions define an additional parameter `ti(memory_order)
tt(order)', which is not available for the non-tt(_explicit) functions (e.g.,
tt(atomic_load(atomic<Type> *ptr)) and tt(atomic_load_explicit(atomic<Type>
*ptr, memory_order order)))

Here are the free functions that are available for all atomic types:
    itemization(
    ithtq(atomic_compare_exchange_strong+nop()(_explicit))(bool
        std::atomic_compare_exchange_strong(_explicit)(std::atomic<Type> *ptr,
        Type *oldValue, Type newValue) noexept)
       (returns tt(ptr->compare_exchange_strong(*oldValue, newValue));)

    ithtq(atomic_compare_exchange_weak(_explicit))(bool
        std::atomic_compare_exchange_weak(_explicit)(std::atomic<Type> *ptr,
        Type *oldValue, Type newValue) noexept)
       (returns tt(ptr->compare_exchange_weak(*oldValue, newValue));)

    ithtq(atomic_exchange(_explicit))(Type
        std::atomic_exchange(_explicit)(std::atomic<Type> *ptr, Type newValue)
        noexept)
       (returns tt(ptr->exchange(newValue));)

    ithtq(atomic_init)(void std::atomic_init(std::atomic<Type> *ptr, Type
        init) noexept)
       (Stores tt(init) em(non)-atomically in tt(*ptr). The object pointed to
        by tt(ptr) must have been default constructed, and as yet no member
        functions must have been called for it.
        This function has no tt(memory_order) parameter;)

    ithtq(atomic_is_lock_free)(bool std::atomic_is_lock_free(std::atomic<Type>
        const *ptr) noexept)
       (returns tt(ptr->is_lock_free()).
        This function has no tt(memory_order) parameter;)

    ithtq(atomic_load(_explicit))(Type
        std::atomic_load(_explicit)(std::atomic<Type> *ptr) noexept)
       (returns tt(ptr->load());)

    ithtq(atomic_store(_explicit))(void
        std::atomic_store(_explicit)(std::atomic<Type> *ptr, Type value)
        noexept)
       (calls tt(ptr->store(value)).)
    )    

In addition to the abovementioned free functions tt(atomic<Integral>) types
also offer the following free member functions:
    itemization(
    ithtq(atomic_fetch_add(_explicit))(Integral
        std::atomic_fetch_add(_explicit)(std::atomic<Integral> *ptr, Integral
        value) noexcept)
       (returns tt(ptr->fetch_add(value));)

    ithtq(atomic_fetch_sub(_explicit))(Integral
        std::atomic_fetch_sub(_explicit)(std::atomic<Integral> *ptr, Integral
        value) noexcept)
       (returns tt(ptr->fetch_sub(value));)

    ithtq(atomic_fetch_and)(Integral
        std::atomic_fetch_and(_explicit)(std::atomic<Integral> *ptr, Integral
        mask) noexcept)
       (returns tt(ptr->fetch_and(value));)


    ithtq(atomic_fetch_or)(Integral
        std::atomic_fetch_or(_explicit)(std::atomic<Integral> *ptr, Integral
        mask) noexcept)
       (returns tt(ptr->fetch_or(value));)


    ithtq(atomic_fetch_xor)(Integral
        std::atomic_fetch_xor(_explicit)(std::atomic<Integral> *ptr, Integral
        mask) noexcept)
       (returns tt(ptr->fetch_xor(mask)).)
    )