- tmp/tmps_rve45d/{from.md → to.md} +405 -142
tmp/tmps_rve45d/{from.md → to.md}
RENAMED
|
@@ -7,38 +7,40 @@ namespace std {
|
|
| 7 |
template<class T> struct atomic_ref {
|
| 8 |
private:
|
| 9 |
T* ptr; // exposition only
|
| 10 |
|
| 11 |
public:
|
| 12 |
-
using value_type = T;
|
| 13 |
static constexpr size_t required_alignment = implementation-defined // required alignment for atomic_ref type's operations;
|
| 14 |
|
| 15 |
static constexpr bool is_always_lock_free = implementation-defined // whether a given atomic_ref type's operations are always lock free;
|
| 16 |
bool is_lock_free() const noexcept;
|
| 17 |
|
| 18 |
-
explicit atomic_ref(T&);
|
| 19 |
-
atomic_ref(const atomic_ref&) noexcept;
|
| 20 |
atomic_ref& operator=(const atomic_ref&) = delete;
|
| 21 |
|
| 22 |
-
void store(
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
operator
|
| 26 |
|
| 27 |
-
|
| 28 |
-
|
|
|
|
| 29 |
memory_order, memory_order) const noexcept;
|
| 30 |
-
bool compare_exchange_strong(
|
| 31 |
memory_order, memory_order) const noexcept;
|
| 32 |
-
bool compare_exchange_weak(
|
| 33 |
memory_order = memory_order::seq_cst) const noexcept;
|
| 34 |
-
bool compare_exchange_strong(
|
| 35 |
memory_order = memory_order::seq_cst) const noexcept;
|
| 36 |
|
| 37 |
-
void wait(
|
| 38 |
-
void notify_one() const noexcept;
|
| 39 |
-
void notify_all() const noexcept;
|
|
|
|
| 40 |
};
|
| 41 |
}
|
| 42 |
```
|
| 43 |
|
| 44 |
An `atomic_ref` object applies atomic operations [[atomics.general]] to
|
|
@@ -63,10 +65,13 @@ through any other `atomic_ref` referencing the same object.
|
|
| 63 |
[*Note 1*: Atomic operations or the `atomic_ref` constructor can
|
| 64 |
acquire a shared resource, such as a lock associated with the referenced
|
| 65 |
object, to enable atomic operations to be applied to the referenced
|
| 66 |
object. — *end note*]
|
| 67 |
|
|
|
|
|
|
|
|
|
|
| 68 |
#### Operations <a id="atomics.ref.ops">[[atomics.ref.ops]]</a>
|
| 69 |
|
| 70 |
``` cpp
|
| 71 |
static constexpr size_t required_alignment;
|
| 72 |
```
|
|
@@ -95,94 +100,103 @@ bool is_lock_free() const noexcept;
|
|
| 95 |
|
| 96 |
*Returns:* `true` if operations on all objects of the type
|
| 97 |
`atomic_ref<T>` are lock-free, `false` otherwise.
|
| 98 |
|
| 99 |
``` cpp
|
| 100 |
-
atomic_ref(T& obj);
|
| 101 |
```
|
| 102 |
|
| 103 |
*Preconditions:* The referenced object is aligned to
|
| 104 |
`required_alignment`.
|
| 105 |
|
| 106 |
*Ensures:* `*this` references `obj`.
|
| 107 |
|
| 108 |
*Throws:* Nothing.
|
| 109 |
|
| 110 |
``` cpp
|
| 111 |
-
atomic_ref(const atomic_ref& ref) noexcept;
|
| 112 |
```
|
| 113 |
|
| 114 |
*Ensures:* `*this` references the object referenced by `ref`.
|
| 115 |
|
| 116 |
``` cpp
|
| 117 |
-
void store(
|
|
|
|
| 118 |
```
|
| 119 |
|
| 120 |
-
*
|
| 121 |
-
|
| 122 |
-
`memory_order::
|
|
|
|
| 123 |
|
| 124 |
*Effects:* Atomically replaces the value referenced by `*ptr` with the
|
| 125 |
value of `desired`. Memory is affected according to the value of
|
| 126 |
`order`.
|
| 127 |
|
| 128 |
``` cpp
|
| 129 |
-
|
| 130 |
```
|
| 131 |
|
|
|
|
|
|
|
| 132 |
*Effects:* Equivalent to:
|
| 133 |
|
| 134 |
``` cpp
|
| 135 |
store(desired);
|
| 136 |
return desired;
|
| 137 |
```
|
| 138 |
|
| 139 |
``` cpp
|
| 140 |
-
|
| 141 |
```
|
| 142 |
|
| 143 |
-
*Preconditions:*
|
| 144 |
-
|
| 145 |
|
| 146 |
*Effects:* Memory is affected according to the value of `order`.
|
| 147 |
|
| 148 |
*Returns:* Atomically returns the value referenced by `*ptr`.
|
| 149 |
|
| 150 |
``` cpp
|
| 151 |
-
operator
|
| 152 |
```
|
| 153 |
|
| 154 |
*Effects:* Equivalent to: `return load();`
|
| 155 |
|
| 156 |
``` cpp
|
| 157 |
-
|
|
|
|
| 158 |
```
|
| 159 |
|
|
|
|
|
|
|
| 160 |
*Effects:* Atomically replaces the value referenced by `*ptr` with
|
| 161 |
`desired`. Memory is affected according to the value of `order`. This
|
| 162 |
operation is an atomic read-modify-write
|
| 163 |
operation [[intro.multithread]].
|
| 164 |
|
| 165 |
*Returns:* Atomically returns the value referenced by `*ptr` immediately
|
| 166 |
before the effects.
|
| 167 |
|
| 168 |
``` cpp
|
| 169 |
-
bool compare_exchange_weak(
|
| 170 |
memory_order success, memory_order failure) const noexcept;
|
| 171 |
|
| 172 |
-
bool compare_exchange_strong(
|
| 173 |
memory_order success, memory_order failure) const noexcept;
|
| 174 |
|
| 175 |
-
bool compare_exchange_weak(
|
| 176 |
memory_order order = memory_order::seq_cst) const noexcept;
|
| 177 |
|
| 178 |
-
bool compare_exchange_strong(
|
| 179 |
memory_order order = memory_order::seq_cst) const noexcept;
|
| 180 |
```
|
| 181 |
|
| 182 |
-
*
|
| 183 |
-
|
|
|
|
|
|
|
| 184 |
|
| 185 |
*Effects:* Retrieves the value in `expected`. It then atomically
|
| 186 |
compares the value representation of the value referenced by `*ptr` for
|
| 187 |
equality with that previously retrieved from `expected`, and if `true`,
|
| 188 |
replaces the value referenced by `*ptr` with that in `desired`. If and
|
|
@@ -216,15 +230,15 @@ compare-and-exchange is in a loop, the weak version will yield better
|
|
| 216 |
performance on some platforms. When a weak compare-and-exchange would
|
| 217 |
require a loop and a strong one would not, the strong one is
|
| 218 |
preferable. — *end note*]
|
| 219 |
|
| 220 |
``` cpp
|
| 221 |
-
void wait(
|
| 222 |
```
|
| 223 |
|
| 224 |
-
*Preconditions:* `order` is
|
| 225 |
-
`memory_order::
|
| 226 |
|
| 227 |
*Effects:* Repeatedly performs the following steps, in order:
|
| 228 |
|
| 229 |
- Evaluates `load(order)` and compares its value representation for
|
| 230 |
equality against that of `old`.
|
|
@@ -234,102 +248,131 @@ void wait(T old, memory_order order = memory_order::seq_cst) const noexcept;
|
|
| 234 |
|
| 235 |
*Remarks:* This function is an atomic waiting operation [[atomics.wait]]
|
| 236 |
on atomic object `*ptr`.
|
| 237 |
|
| 238 |
``` cpp
|
| 239 |
-
void notify_one() const noexcept;
|
| 240 |
```
|
| 241 |
|
|
|
|
|
|
|
| 242 |
*Effects:* Unblocks the execution of at least one atomic waiting
|
| 243 |
operation on `*ptr` that is eligible to be unblocked [[atomics.wait]] by
|
| 244 |
this call, if any such atomic waiting operations exist.
|
| 245 |
|
| 246 |
*Remarks:* This function is an atomic notifying
|
| 247 |
operation [[atomics.wait]] on atomic object `*ptr`.
|
| 248 |
|
| 249 |
``` cpp
|
| 250 |
-
void notify_all() const noexcept;
|
| 251 |
```
|
| 252 |
|
|
|
|
|
|
|
| 253 |
*Effects:* Unblocks the execution of all atomic waiting operations on
|
| 254 |
`*ptr` that are eligible to be unblocked [[atomics.wait]] by this call.
|
| 255 |
|
| 256 |
*Remarks:* This function is an atomic notifying
|
| 257 |
operation [[atomics.wait]] on atomic object `*ptr`.
|
| 258 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 259 |
#### Specializations for integral types <a id="atomics.ref.int">[[atomics.ref.int]]</a>
|
| 260 |
|
| 261 |
-
There are specializations of the `atomic_ref` class template for
|
| 262 |
-
integral types `
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
`wchar_t`, and any other types needed by the typedefs in the header
|
| 266 |
-
`<cstdint>`. For each such type `integral-type`, the specialization
|
| 267 |
-
`atomic_ref<integral-type>` provides additional atomic operations
|
| 268 |
-
appropriate to integral types.
|
| 269 |
|
| 270 |
[*Note 1*: The specialization `atomic_ref<bool>` uses the primary
|
| 271 |
template [[atomics.ref.generic]]. — *end note*]
|
| 272 |
|
|
|
|
|
|
|
|
|
|
| 273 |
``` cpp
|
| 274 |
namespace std {
|
| 275 |
template<> struct atomic_ref<integral-type> {
|
| 276 |
private:
|
| 277 |
integral-type* ptr; // exposition only
|
| 278 |
|
| 279 |
public:
|
| 280 |
-
using value_type = integral-type;
|
| 281 |
using difference_type = value_type;
|
| 282 |
static constexpr size_t required_alignment = implementation-defined // required alignment for atomic_ref type's operations;
|
| 283 |
|
| 284 |
static constexpr bool is_always_lock_free = implementation-defined // whether a given atomic_ref type's operations are always lock free;
|
| 285 |
bool is_lock_free() const noexcept;
|
| 286 |
|
| 287 |
-
explicit atomic_ref(integral-type&);
|
| 288 |
-
atomic_ref(const atomic_ref&) noexcept;
|
| 289 |
atomic_ref& operator=(const atomic_ref&) = delete;
|
| 290 |
|
| 291 |
-
void store(
|
| 292 |
-
|
| 293 |
-
|
| 294 |
-
operator
|
| 295 |
|
| 296 |
-
|
| 297 |
memory_order = memory_order::seq_cst) const noexcept;
|
| 298 |
-
bool compare_exchange_weak(
|
| 299 |
memory_order, memory_order) const noexcept;
|
| 300 |
-
bool compare_exchange_strong(
|
| 301 |
memory_order, memory_order) const noexcept;
|
| 302 |
-
bool compare_exchange_weak(
|
| 303 |
memory_order = memory_order::seq_cst) const noexcept;
|
| 304 |
-
bool compare_exchange_strong(
|
| 305 |
memory_order = memory_order::seq_cst) const noexcept;
|
| 306 |
|
| 307 |
-
|
| 308 |
memory_order = memory_order::seq_cst) const noexcept;
|
| 309 |
-
|
| 310 |
memory_order = memory_order::seq_cst) const noexcept;
|
| 311 |
-
|
| 312 |
memory_order = memory_order::seq_cst) const noexcept;
|
| 313 |
-
|
| 314 |
memory_order = memory_order::seq_cst) const noexcept;
|
| 315 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 316 |
memory_order = memory_order::seq_cst) const noexcept;
|
| 317 |
|
| 318 |
-
|
| 319 |
-
|
| 320 |
-
|
| 321 |
-
|
| 322 |
-
|
| 323 |
-
|
| 324 |
-
|
| 325 |
-
|
| 326 |
-
|
| 327 |
|
| 328 |
-
void wait(
|
| 329 |
-
void notify_one() const noexcept;
|
| 330 |
-
void notify_all() const noexcept;
|
|
|
|
| 331 |
};
|
| 332 |
}
|
| 333 |
```
|
| 334 |
|
| 335 |
Descriptions are provided below only for members that differ from the
|
|
@@ -338,107 +381,177 @@ primary template.
|
|
| 338 |
The following operations perform arithmetic computations. The
|
| 339 |
correspondence among key, operator, and computation is specified in
|
| 340 |
[[atomic.types.int.comp]].
|
| 341 |
|
| 342 |
``` cpp
|
| 343 |
-
|
| 344 |
memory_order order = memory_order::seq_cst) const noexcept;
|
| 345 |
```
|
| 346 |
|
|
|
|
|
|
|
| 347 |
*Effects:* Atomically replaces the value referenced by `*ptr` with the
|
| 348 |
result of the computation applied to the value referenced by `*ptr` and
|
| 349 |
the given operand. Memory is affected according to the value of `order`.
|
| 350 |
These operations are atomic read-modify-write
|
| 351 |
operations [[intro.races]].
|
| 352 |
|
| 353 |
*Returns:* Atomically, the value referenced by `*ptr` immediately before
|
| 354 |
the effects.
|
| 355 |
|
| 356 |
-
*Remarks:*
|
| 357 |
-
value and parameters were converted
|
| 358 |
-
types, the computation performed on
|
| 359 |
-
converted back to the signed type.
|
| 360 |
|
| 361 |
[*Note 1*: There are no undefined results arising from the
|
| 362 |
computation. — *end note*]
|
| 363 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 364 |
``` cpp
|
| 365 |
-
|
|
|
|
| 366 |
```
|
| 367 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 368 |
*Effects:* Equivalent to:
|
| 369 |
`return fetch_`*`key`*`(operand) `*`op`*` operand;`
|
| 370 |
|
| 371 |
#### Specializations for floating-point types <a id="atomics.ref.float">[[atomics.ref.float]]</a>
|
| 372 |
|
| 373 |
There are specializations of the `atomic_ref` class template for all
|
| 374 |
-
|
| 375 |
-
|
| 376 |
-
|
| 377 |
-
|
|
|
|
|
|
|
| 378 |
|
| 379 |
``` cpp
|
| 380 |
namespace std {
|
| 381 |
template<> struct atomic_ref<floating-point-type> {
|
| 382 |
private:
|
| 383 |
floating-point-type* ptr; // exposition only
|
| 384 |
|
| 385 |
public:
|
| 386 |
-
using value_type = floating-point-type;
|
| 387 |
using difference_type = value_type;
|
| 388 |
static constexpr size_t required_alignment = implementation-defined // required alignment for atomic_ref type's operations;
|
| 389 |
|
| 390 |
static constexpr bool is_always_lock_free = implementation-defined // whether a given atomic_ref type's operations are always lock free;
|
| 391 |
bool is_lock_free() const noexcept;
|
| 392 |
|
| 393 |
-
explicit atomic_ref(floating-point-type&);
|
| 394 |
-
atomic_ref(const atomic_ref&) noexcept;
|
| 395 |
atomic_ref& operator=(const atomic_ref&) = delete;
|
| 396 |
|
| 397 |
-
void store(
|
| 398 |
-
|
| 399 |
-
|
| 400 |
-
|
|
|
|
| 401 |
|
| 402 |
-
|
| 403 |
memory_order = memory_order::seq_cst) const noexcept;
|
| 404 |
-
bool compare_exchange_weak(
|
| 405 |
memory_order, memory_order) const noexcept;
|
| 406 |
-
bool compare_exchange_strong(
|
| 407 |
memory_order, memory_order) const noexcept;
|
| 408 |
-
bool compare_exchange_weak(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 409 |
memory_order = memory_order::seq_cst) const noexcept;
|
| 410 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 411 |
memory_order = memory_order::seq_cst) const noexcept;
|
| 412 |
|
| 413 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 414 |
memory_order = memory_order::seq_cst) const noexcept;
|
| 415 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 416 |
memory_order = memory_order::seq_cst) const noexcept;
|
| 417 |
|
| 418 |
-
|
| 419 |
-
|
| 420 |
|
| 421 |
-
void wait(
|
| 422 |
-
|
| 423 |
-
void
|
|
|
|
|
|
|
| 424 |
};
|
| 425 |
}
|
| 426 |
```
|
| 427 |
|
| 428 |
Descriptions are provided below only for members that differ from the
|
| 429 |
primary template.
|
| 430 |
|
| 431 |
The following operations perform arithmetic computations. The
|
| 432 |
correspondence among key, operator, and computation is specified in
|
| 433 |
-
[[atomic.types.int.comp]]
|
|
|
|
|
|
|
| 434 |
|
| 435 |
``` cpp
|
| 436 |
-
|
| 437 |
memory_order order = memory_order::seq_cst) const noexcept;
|
| 438 |
```
|
| 439 |
|
|
|
|
|
|
|
| 440 |
*Effects:* Atomically replaces the value referenced by `*ptr` with the
|
| 441 |
result of the computation applied to the value referenced by `*ptr` and
|
| 442 |
the given operand. Memory is affected according to the value of `order`.
|
| 443 |
These operations are atomic read-modify-write
|
| 444 |
operations [[intro.races]].
|
|
@@ -448,71 +561,167 @@ the effects.
|
|
| 448 |
|
| 449 |
*Remarks:* If the result is not a representable value for its
|
| 450 |
type [[expr.pre]], the result is unspecified, but the operations
|
| 451 |
otherwise have no undefined behavior. Atomic arithmetic operations on
|
| 452 |
*`floating-point-type`* should conform to the
|
| 453 |
-
`std::numeric_limits<
|
| 454 |
-
|
| 455 |
environment [[cfenv]] for atomic arithmetic operations on
|
| 456 |
*`floating-point-type`* may be different than the calling thread’s
|
| 457 |
floating-point environment.
|
| 458 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 459 |
``` cpp
|
| 460 |
-
|
|
|
|
| 461 |
```
|
| 462 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 463 |
*Effects:* Equivalent to:
|
| 464 |
`return fetch_`*`key`*`(operand) `*`op`*` operand;`
|
| 465 |
|
| 466 |
-
####
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 467 |
|
| 468 |
``` cpp
|
| 469 |
namespace std {
|
| 470 |
-
template<
|
| 471 |
private:
|
| 472 |
-
|
| 473 |
|
| 474 |
public:
|
| 475 |
-
using value_type =
|
| 476 |
using difference_type = ptrdiff_t;
|
| 477 |
static constexpr size_t required_alignment = implementation-defined // required alignment for atomic_ref type's operations;
|
| 478 |
|
| 479 |
static constexpr bool is_always_lock_free = implementation-defined // whether a given atomic_ref type's operations are always lock free;
|
| 480 |
bool is_lock_free() const noexcept;
|
| 481 |
|
| 482 |
-
explicit atomic_ref(
|
| 483 |
-
atomic_ref(const atomic_ref&) noexcept;
|
| 484 |
atomic_ref& operator=(const atomic_ref&) = delete;
|
| 485 |
|
| 486 |
-
void store(
|
| 487 |
-
|
| 488 |
-
|
| 489 |
-
operator
|
| 490 |
|
| 491 |
-
|
| 492 |
-
|
|
|
|
| 493 |
memory_order, memory_order) const noexcept;
|
| 494 |
-
bool compare_exchange_strong(
|
| 495 |
memory_order, memory_order) const noexcept;
|
| 496 |
-
bool compare_exchange_weak(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 497 |
memory_order = memory_order::seq_cst) const noexcept;
|
| 498 |
-
|
|
|
|
|
|
|
| 499 |
memory_order = memory_order::seq_cst) const noexcept;
|
| 500 |
|
| 501 |
-
|
| 502 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 503 |
|
| 504 |
-
|
| 505 |
-
|
| 506 |
-
|
| 507 |
-
|
| 508 |
-
|
| 509 |
-
|
| 510 |
|
| 511 |
-
void wait(
|
| 512 |
-
void notify_one() const noexcept;
|
| 513 |
-
void notify_all() const noexcept;
|
|
|
|
| 514 |
};
|
| 515 |
}
|
| 516 |
```
|
| 517 |
|
| 518 |
Descriptions are provided below only for members that differ from the
|
|
@@ -521,14 +730,18 @@ primary template.
|
|
| 521 |
The following operations perform arithmetic computations. The
|
| 522 |
correspondence among key, operator, and computation is specified in
|
| 523 |
[[atomic.types.pointer.comp]].
|
| 524 |
|
| 525 |
``` cpp
|
| 526 |
-
|
|
|
|
| 527 |
```
|
| 528 |
|
| 529 |
-
*
|
|
|
|
|
|
|
|
|
|
| 530 |
|
| 531 |
*Effects:* Atomically replaces the value referenced by `*ptr` with the
|
| 532 |
result of the computation applied to the value referenced by `*ptr` and
|
| 533 |
the given operand. Memory is affected according to the value of `order`.
|
| 534 |
These operations are atomic read-modify-write
|
|
@@ -538,38 +751,88 @@ operations [[intro.races]].
|
|
| 538 |
the effects.
|
| 539 |
|
| 540 |
*Remarks:* The result may be an undefined address, but the operations
|
| 541 |
otherwise have no undefined behavior.
|
| 542 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 543 |
``` cpp
|
| 544 |
-
|
|
|
|
| 545 |
```
|
| 546 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 547 |
*Effects:* Equivalent to:
|
| 548 |
`return fetch_`*`key`*`(operand) `*`op`*` operand;`
|
| 549 |
|
| 550 |
#### Member operators common to integers and pointers to objects <a id="atomics.ref.memop">[[atomics.ref.memop]]</a>
|
| 551 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 552 |
``` cpp
|
| 553 |
-
value_type operator++(int) const noexcept;
|
| 554 |
```
|
| 555 |
|
|
|
|
|
|
|
| 556 |
*Effects:* Equivalent to: `return fetch_add(1);`
|
| 557 |
|
| 558 |
``` cpp
|
| 559 |
-
value_type operator--(int) const noexcept;
|
| 560 |
```
|
| 561 |
|
|
|
|
|
|
|
| 562 |
*Effects:* Equivalent to: `return fetch_sub(1);`
|
| 563 |
|
| 564 |
``` cpp
|
| 565 |
-
value_type operator++() const noexcept;
|
| 566 |
```
|
| 567 |
|
|
|
|
|
|
|
| 568 |
*Effects:* Equivalent to: `return fetch_add(1) + 1;`
|
| 569 |
|
| 570 |
``` cpp
|
| 571 |
-
value_type operator--() const noexcept;
|
| 572 |
```
|
| 573 |
|
|
|
|
|
|
|
| 574 |
*Effects:* Equivalent to: `return fetch_sub(1) - 1;`
|
| 575 |
|
|
|
|
| 7 |
template<class T> struct atomic_ref {
|
| 8 |
private:
|
| 9 |
T* ptr; // exposition only
|
| 10 |
|
| 11 |
public:
|
| 12 |
+
using value_type = remove_cv_t<T>;
|
| 13 |
static constexpr size_t required_alignment = implementation-defined // required alignment for atomic_ref type's operations;
|
| 14 |
|
| 15 |
static constexpr bool is_always_lock_free = implementation-defined // whether a given atomic_ref type's operations are always lock free;
|
| 16 |
bool is_lock_free() const noexcept;
|
| 17 |
|
| 18 |
+
constexpr explicit atomic_ref(T&);
|
| 19 |
+
constexpr atomic_ref(const atomic_ref&) noexcept;
|
| 20 |
atomic_ref& operator=(const atomic_ref&) = delete;
|
| 21 |
|
| 22 |
+
constexpr void store(value_type, memory_order = memory_order::seq_cst) const noexcept;
|
| 23 |
+
constexpr value_type operator=(value_type) const noexcept;
|
| 24 |
+
constexpr value_type load(memory_order = memory_order::seq_cst) const noexcept;
|
| 25 |
+
constexpr operator value_type() const noexcept;
|
| 26 |
|
| 27 |
+
constexpr value_type exchange(value_type,
|
| 28 |
+
memory_order = memory_order::seq_cst) const noexcept;
|
| 29 |
+
constexpr bool compare_exchange_weak(value_type&, value_type,
|
| 30 |
memory_order, memory_order) const noexcept;
|
| 31 |
+
constexpr bool compare_exchange_strong(value_type&, value_type,
|
| 32 |
memory_order, memory_order) const noexcept;
|
| 33 |
+
constexpr bool compare_exchange_weak(value_type&, value_type,
|
| 34 |
memory_order = memory_order::seq_cst) const noexcept;
|
| 35 |
+
constexpr bool compare_exchange_strong(value_type&, value_type,
|
| 36 |
memory_order = memory_order::seq_cst) const noexcept;
|
| 37 |
|
| 38 |
+
constexpr void wait(value_type, memory_order = memory_order::seq_cst) const noexcept;
|
| 39 |
+
constexpr void notify_one() const noexcept;
|
| 40 |
+
constexpr void notify_all() const noexcept;
|
| 41 |
+
constexpr T* address() const noexcept;
|
| 42 |
};
|
| 43 |
}
|
| 44 |
```
|
| 45 |
|
| 46 |
An `atomic_ref` object applies atomic operations [[atomics.general]] to
|
|
|
|
| 65 |
[*Note 1*: Atomic operations or the `atomic_ref` constructor can
|
| 66 |
acquire a shared resource, such as a lock associated with the referenced
|
| 67 |
object, to enable atomic operations to be applied to the referenced
|
| 68 |
object. — *end note*]
|
| 69 |
|
| 70 |
+
The program is ill-formed if `is_always_lock_free` is `false` and
|
| 71 |
+
`is_volatile_v<T>` is `true`.
|
| 72 |
+
|
| 73 |
#### Operations <a id="atomics.ref.ops">[[atomics.ref.ops]]</a>
|
| 74 |
|
| 75 |
``` cpp
|
| 76 |
static constexpr size_t required_alignment;
|
| 77 |
```
|
|
|
|
| 100 |
|
| 101 |
*Returns:* `true` if operations on all objects of the type
|
| 102 |
`atomic_ref<T>` are lock-free, `false` otherwise.
|
| 103 |
|
| 104 |
``` cpp
|
| 105 |
+
constexpr atomic_ref(T& obj);
|
| 106 |
```
|
| 107 |
|
| 108 |
*Preconditions:* The referenced object is aligned to
|
| 109 |
`required_alignment`.
|
| 110 |
|
| 111 |
*Ensures:* `*this` references `obj`.
|
| 112 |
|
| 113 |
*Throws:* Nothing.
|
| 114 |
|
| 115 |
``` cpp
|
| 116 |
+
constexpr atomic_ref(const atomic_ref& ref) noexcept;
|
| 117 |
```
|
| 118 |
|
| 119 |
*Ensures:* `*this` references the object referenced by `ref`.
|
| 120 |
|
| 121 |
``` cpp
|
| 122 |
+
constexpr void store(value_type desired,
|
| 123 |
+
memory_order order = memory_order::seq_cst) const noexcept;
|
| 124 |
```
|
| 125 |
|
| 126 |
+
*Constraints:* `is_const_v<T>` is `false`.
|
| 127 |
+
|
| 128 |
+
*Preconditions:* `order` is `memory_order::relaxed`,
|
| 129 |
+
`memory_order::release`, or `memory_order::seq_cst`.
|
| 130 |
|
| 131 |
*Effects:* Atomically replaces the value referenced by `*ptr` with the
|
| 132 |
value of `desired`. Memory is affected according to the value of
|
| 133 |
`order`.
|
| 134 |
|
| 135 |
``` cpp
|
| 136 |
+
constexpr value_type operator=(value_type desired) const noexcept;
|
| 137 |
```
|
| 138 |
|
| 139 |
+
*Constraints:* `is_const_v<T>` is `false`.
|
| 140 |
+
|
| 141 |
*Effects:* Equivalent to:
|
| 142 |
|
| 143 |
``` cpp
|
| 144 |
store(desired);
|
| 145 |
return desired;
|
| 146 |
```
|
| 147 |
|
| 148 |
``` cpp
|
| 149 |
+
constexpr value_type load(memory_order order = memory_order::seq_cst) const noexcept;
|
| 150 |
```
|
| 151 |
|
| 152 |
+
*Preconditions:* `order` is `memory_order::relaxed`,
|
| 153 |
+
`memory_order::acquire`, or `memory_order::seq_cst`.
|
| 154 |
|
| 155 |
*Effects:* Memory is affected according to the value of `order`.
|
| 156 |
|
| 157 |
*Returns:* Atomically returns the value referenced by `*ptr`.
|
| 158 |
|
| 159 |
``` cpp
|
| 160 |
+
constexpr operator value_type() const noexcept;
|
| 161 |
```
|
| 162 |
|
| 163 |
*Effects:* Equivalent to: `return load();`
|
| 164 |
|
| 165 |
``` cpp
|
| 166 |
+
constexpr value_type exchange(value_type desired,
|
| 167 |
+
memory_order order = memory_order::seq_cst) const noexcept;
|
| 168 |
```
|
| 169 |
|
| 170 |
+
*Constraints:* `is_const_v<T>` is `false`.
|
| 171 |
+
|
| 172 |
*Effects:* Atomically replaces the value referenced by `*ptr` with
|
| 173 |
`desired`. Memory is affected according to the value of `order`. This
|
| 174 |
operation is an atomic read-modify-write
|
| 175 |
operation [[intro.multithread]].
|
| 176 |
|
| 177 |
*Returns:* Atomically returns the value referenced by `*ptr` immediately
|
| 178 |
before the effects.
|
| 179 |
|
| 180 |
``` cpp
|
| 181 |
+
constexpr bool compare_exchange_weak(value_type& expected, value_type desired,
|
| 182 |
memory_order success, memory_order failure) const noexcept;
|
| 183 |
|
| 184 |
+
constexpr bool compare_exchange_strong(value_type& expected, value_type desired,
|
| 185 |
memory_order success, memory_order failure) const noexcept;
|
| 186 |
|
| 187 |
+
constexpr bool compare_exchange_weak(value_type& expected, value_type desired,
|
| 188 |
memory_order order = memory_order::seq_cst) const noexcept;
|
| 189 |
|
| 190 |
+
constexpr bool compare_exchange_strong(value_type& expected, value_type desired,
|
| 191 |
memory_order order = memory_order::seq_cst) const noexcept;
|
| 192 |
```
|
| 193 |
|
| 194 |
+
*Constraints:* `is_const_v<T>` is `false`.
|
| 195 |
+
|
| 196 |
+
*Preconditions:* `failure` is `memory_order::relaxed`,
|
| 197 |
+
`memory_order::acquire`, or `memory_order::seq_cst`.
|
| 198 |
|
| 199 |
*Effects:* Retrieves the value in `expected`. It then atomically
|
| 200 |
compares the value representation of the value referenced by `*ptr` for
|
| 201 |
equality with that previously retrieved from `expected`, and if `true`,
|
| 202 |
replaces the value referenced by `*ptr` with that in `desired`. If and
|
|
|
|
| 230 |
performance on some platforms. When a weak compare-and-exchange would
|
| 231 |
require a loop and a strong one would not, the strong one is
|
| 232 |
preferable. — *end note*]
|
| 233 |
|
| 234 |
``` cpp
|
| 235 |
+
constexpr void wait(value_type old, memory_order order = memory_order::seq_cst) const noexcept;
|
| 236 |
```
|
| 237 |
|
| 238 |
+
*Preconditions:* `order` is `memory_order::relaxed`,
|
| 239 |
+
`memory_order::acquire`, or `memory_order::seq_cst`.
|
| 240 |
|
| 241 |
*Effects:* Repeatedly performs the following steps, in order:
|
| 242 |
|
| 243 |
- Evaluates `load(order)` and compares its value representation for
|
| 244 |
equality against that of `old`.
|
|
|
|
| 248 |
|
| 249 |
*Remarks:* This function is an atomic waiting operation [[atomics.wait]]
|
| 250 |
on atomic object `*ptr`.
|
| 251 |
|
| 252 |
``` cpp
|
| 253 |
+
constexpr void notify_one() const noexcept;
|
| 254 |
```
|
| 255 |
|
| 256 |
+
*Constraints:* `is_const_v<T>` is `false`.
|
| 257 |
+
|
| 258 |
*Effects:* Unblocks the execution of at least one atomic waiting
|
| 259 |
operation on `*ptr` that is eligible to be unblocked [[atomics.wait]] by
|
| 260 |
this call, if any such atomic waiting operations exist.
|
| 261 |
|
| 262 |
*Remarks:* This function is an atomic notifying
|
| 263 |
operation [[atomics.wait]] on atomic object `*ptr`.
|
| 264 |
|
| 265 |
``` cpp
|
| 266 |
+
constexpr void notify_all() const noexcept;
|
| 267 |
```
|
| 268 |
|
| 269 |
+
*Constraints:* `is_const_v<T>` is `false`.
|
| 270 |
+
|
| 271 |
*Effects:* Unblocks the execution of all atomic waiting operations on
|
| 272 |
`*ptr` that are eligible to be unblocked [[atomics.wait]] by this call.
|
| 273 |
|
| 274 |
*Remarks:* This function is an atomic notifying
|
| 275 |
operation [[atomics.wait]] on atomic object `*ptr`.
|
| 276 |
|
| 277 |
+
``` cpp
|
| 278 |
+
constexpr T* address() const noexcept;
|
| 279 |
+
```
|
| 280 |
+
|
| 281 |
+
*Returns:* `ptr`.
|
| 282 |
+
|
| 283 |
#### Specializations for integral types <a id="atomics.ref.int">[[atomics.ref.int]]</a>
|
| 284 |
|
| 285 |
+
There are specializations of the `atomic_ref` class template for all
|
| 286 |
+
integral types except cv `bool`. For each such type `integral-type`, the
|
| 287 |
+
specialization `atomic_ref<integral-type>` provides additional atomic
|
| 288 |
+
operations appropriate to integral types.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 289 |
|
| 290 |
[*Note 1*: The specialization `atomic_ref<bool>` uses the primary
|
| 291 |
template [[atomics.ref.generic]]. — *end note*]
|
| 292 |
|
| 293 |
+
The program is ill-formed if `is_always_lock_free` is `false` and
|
| 294 |
+
`is_volatile_v<integral-type>` is `true`.
|
| 295 |
+
|
| 296 |
``` cpp
|
| 297 |
namespace std {
|
| 298 |
template<> struct atomic_ref<integral-type> {
|
| 299 |
private:
|
| 300 |
integral-type* ptr; // exposition only
|
| 301 |
|
| 302 |
public:
|
| 303 |
+
using value_type = remove_cv_t<integral-type>;
|
| 304 |
using difference_type = value_type;
|
| 305 |
static constexpr size_t required_alignment = implementation-defined // required alignment for atomic_ref type's operations;
|
| 306 |
|
| 307 |
static constexpr bool is_always_lock_free = implementation-defined // whether a given atomic_ref type's operations are always lock free;
|
| 308 |
bool is_lock_free() const noexcept;
|
| 309 |
|
| 310 |
+
constexpr explicit atomic_ref(integral-type&);
|
| 311 |
+
constexpr atomic_ref(const atomic_ref&) noexcept;
|
| 312 |
atomic_ref& operator=(const atomic_ref&) = delete;
|
| 313 |
|
| 314 |
+
constexpr void store(value_type, memory_order = memory_order::seq_cst) const noexcept;
|
| 315 |
+
constexpr value_type operator=(value_type) const noexcept;
|
| 316 |
+
constexpr value_type load(memory_order = memory_order::seq_cst) const noexcept;
|
| 317 |
+
constexpr operator value_type() const noexcept;
|
| 318 |
|
| 319 |
+
constexpr value_type exchange(value_type,
|
| 320 |
memory_order = memory_order::seq_cst) const noexcept;
|
| 321 |
+
constexpr bool compare_exchange_weak(value_type&, value_type,
|
| 322 |
memory_order, memory_order) const noexcept;
|
| 323 |
+
constexpr bool compare_exchange_strong(value_type&, value_type,
|
| 324 |
memory_order, memory_order) const noexcept;
|
| 325 |
+
constexpr bool compare_exchange_weak(value_type&, value_type,
|
| 326 |
memory_order = memory_order::seq_cst) const noexcept;
|
| 327 |
+
constexpr bool compare_exchange_strong(value_type&, value_type,
|
| 328 |
memory_order = memory_order::seq_cst) const noexcept;
|
| 329 |
|
| 330 |
+
constexpr value_type fetch_add(value_type,
|
| 331 |
memory_order = memory_order::seq_cst) const noexcept;
|
| 332 |
+
constexpr value_type fetch_sub(value_type,
|
| 333 |
memory_order = memory_order::seq_cst) const noexcept;
|
| 334 |
+
constexpr value_type fetch_and(value_type,
|
| 335 |
memory_order = memory_order::seq_cst) const noexcept;
|
| 336 |
+
constexpr value_type fetch_or(value_type,
|
| 337 |
memory_order = memory_order::seq_cst) const noexcept;
|
| 338 |
+
constexpr value_type fetch_xor(value_type,
|
| 339 |
+
memory_order = memory_order::seq_cst) const noexcept;
|
| 340 |
+
constexpr value_type fetch_max(value_type,
|
| 341 |
+
memory_order = memory_order::seq_cst) const noexcept;
|
| 342 |
+
constexpr value_type fetch_min(value_type,
|
| 343 |
+
memory_order = memory_order::seq_cst) const noexcept;
|
| 344 |
+
|
| 345 |
+
constexpr void store_add(value_type,
|
| 346 |
+
memory_order = memory_order::seq_cst) const noexcept;
|
| 347 |
+
constexpr void store_sub(value_type,
|
| 348 |
+
memory_order = memory_order::seq_cst) const noexcept;
|
| 349 |
+
constexpr void store_and(value_type,
|
| 350 |
+
memory_order = memory_order::seq_cst) const noexcept;
|
| 351 |
+
constexpr void store_or(value_type,
|
| 352 |
+
memory_order = memory_order::seq_cst) const noexcept;
|
| 353 |
+
constexpr void store_xor(value_type,
|
| 354 |
+
memory_order = memory_order::seq_cst) const noexcept;
|
| 355 |
+
constexpr void store_max(value_type,
|
| 356 |
+
memory_order = memory_order::seq_cst) const noexcept;
|
| 357 |
+
constexpr void store_min(value_type,
|
| 358 |
memory_order = memory_order::seq_cst) const noexcept;
|
| 359 |
|
| 360 |
+
constexpr value_type operator++(int) const noexcept;
|
| 361 |
+
constexpr value_type operator--(int) const noexcept;
|
| 362 |
+
constexpr value_type operator++() const noexcept;
|
| 363 |
+
constexpr value_type operator--() const noexcept;
|
| 364 |
+
constexpr value_type operator+=(value_type) const noexcept;
|
| 365 |
+
constexpr value_type operator-=(value_type) const noexcept;
|
| 366 |
+
constexpr value_type operator&=(value_type) const noexcept;
|
| 367 |
+
constexpr value_type operator|=(value_type) const noexcept;
|
| 368 |
+
constexpr value_type operator^=(value_type) const noexcept;
|
| 369 |
|
| 370 |
+
constexpr void wait(value_type, memory_order = memory_order::seq_cst) const noexcept;
|
| 371 |
+
constexpr void notify_one() const noexcept;
|
| 372 |
+
constexpr void notify_all() const noexcept;
|
| 373 |
+
constexpr integral-type* address() const noexcept;
|
| 374 |
};
|
| 375 |
}
|
| 376 |
```
|
| 377 |
|
| 378 |
Descriptions are provided below only for members that differ from the
|
|
|
|
| 381 |
The following operations perform arithmetic computations. The
|
| 382 |
correspondence among key, operator, and computation is specified in
|
| 383 |
[[atomic.types.int.comp]].
|
| 384 |
|
| 385 |
``` cpp
|
| 386 |
+
constexpr value_type fetch_key(value_type operand,
|
| 387 |
memory_order order = memory_order::seq_cst) const noexcept;
|
| 388 |
```
|
| 389 |
|
| 390 |
+
*Constraints:* `is_const_v<`*`integral-type`*`>` is `false`.
|
| 391 |
+
|
| 392 |
*Effects:* Atomically replaces the value referenced by `*ptr` with the
|
| 393 |
result of the computation applied to the value referenced by `*ptr` and
|
| 394 |
the given operand. Memory is affected according to the value of `order`.
|
| 395 |
These operations are atomic read-modify-write
|
| 396 |
operations [[intro.races]].
|
| 397 |
|
| 398 |
*Returns:* Atomically, the value referenced by `*ptr` immediately before
|
| 399 |
the effects.
|
| 400 |
|
| 401 |
+
*Remarks:* Except for `fetch_max` and `fetch_min`, for signed integer
|
| 402 |
+
types the result is as if the object value and parameters were converted
|
| 403 |
+
to their corresponding unsigned types, the computation performed on
|
| 404 |
+
those types, and the result converted back to the signed type.
|
| 405 |
|
| 406 |
[*Note 1*: There are no undefined results arising from the
|
| 407 |
computation. — *end note*]
|
| 408 |
|
| 409 |
+
For `fetch_max` and `fetch_min`, the maximum and minimum computation is
|
| 410 |
+
performed as if by `max` and `min` algorithms [[alg.min.max]],
|
| 411 |
+
respectively, with the object value and the first parameter as the
|
| 412 |
+
arguments.
|
| 413 |
+
|
| 414 |
``` cpp
|
| 415 |
+
constexpr void store_key(value_type operand,
|
| 416 |
+
memory_order order = memory_order::seq_cst) const noexcept;
|
| 417 |
```
|
| 418 |
|
| 419 |
+
*Preconditions:* `order` is `memory_order::relaxed`,
|
| 420 |
+
`memory_order::release`, or `memory_order::seq_cst`.
|
| 421 |
+
|
| 422 |
+
*Effects:* Atomically replaces the value referenced by `*ptr` with the
|
| 423 |
+
result of the computation applied to the value referenced by `*ptr` and
|
| 424 |
+
the given `operand`. Memory is affected according to the value of
|
| 425 |
+
`order`. These operations are atomic modify-write
|
| 426 |
+
operations [[atomics.order]].
|
| 427 |
+
|
| 428 |
+
*Remarks:* Except for `store_max` and `store_min`, for signed integer
|
| 429 |
+
types, the result is as if `*ptr` and parameters were converted to their
|
| 430 |
+
corresponding unsigned types, the computation performed on those types,
|
| 431 |
+
and the result converted back to the signed type.
|
| 432 |
+
|
| 433 |
+
[*Note 2*: There are no undefined results arising from the
|
| 434 |
+
computation. — *end note*]
|
| 435 |
+
|
| 436 |
+
For `store_max` and `store_min`, the maximum and minimum computation is
|
| 437 |
+
performed as if by `max` and `min` algorithms [[alg.min.max]],
|
| 438 |
+
respectively, with `*ptr` and the first parameter as the arguments.
|
| 439 |
+
|
| 440 |
+
``` cpp
|
| 441 |
+
constexpr value_type operator op=(value_type operand) const noexcept;
|
| 442 |
+
```
|
| 443 |
+
|
| 444 |
+
*Constraints:* `is_const_v<`*`integral-type`*`>` is `false`.
|
| 445 |
+
|
| 446 |
*Effects:* Equivalent to:
|
| 447 |
`return fetch_`*`key`*`(operand) `*`op`*` operand;`
|
| 448 |
|
| 449 |
#### Specializations for floating-point types <a id="atomics.ref.float">[[atomics.ref.float]]</a>
|
| 450 |
|
| 451 |
There are specializations of the `atomic_ref` class template for all
|
| 452 |
+
floating-point types. For each such type `floating-point-type`, the
|
| 453 |
+
specialization `atomic_ref<floating-point-type>` provides additional
|
| 454 |
+
atomic operations appropriate to floating-point types.
|
| 455 |
+
|
| 456 |
+
The program is ill-formed if `is_always_lock_free` is `false` and
|
| 457 |
+
`is_volatile_v<floating-point-type>` is `true`.
|
| 458 |
|
| 459 |
``` cpp
|
| 460 |
namespace std {
|
| 461 |
template<> struct atomic_ref<floating-point-type> {
|
| 462 |
private:
|
| 463 |
floating-point-type* ptr; // exposition only
|
| 464 |
|
| 465 |
public:
|
| 466 |
+
using value_type = remove_cv_t<floating-point-type>;
|
| 467 |
using difference_type = value_type;
|
| 468 |
static constexpr size_t required_alignment = implementation-defined // required alignment for atomic_ref type's operations;
|
| 469 |
|
| 470 |
static constexpr bool is_always_lock_free = implementation-defined // whether a given atomic_ref type's operations are always lock free;
|
| 471 |
bool is_lock_free() const noexcept;
|
| 472 |
|
| 473 |
+
constexpr explicit atomic_ref(floating-point-type&);
|
| 474 |
+
constexpr atomic_ref(const atomic_ref&) noexcept;
|
| 475 |
atomic_ref& operator=(const atomic_ref&) = delete;
|
| 476 |
|
| 477 |
+
constexpr void store(value_type,
|
| 478 |
+
memory_order = memory_order::seq_cst) const noexcept;
|
| 479 |
+
constexpr value_type operator=(value_type) const noexcept;
|
| 480 |
+
constexpr value_type load(memory_order = memory_order::seq_cst) const noexcept;
|
| 481 |
+
constexpr operator value_type() const noexcept;
|
| 482 |
|
| 483 |
+
constexpr value_type exchange(value_type,
|
| 484 |
memory_order = memory_order::seq_cst) const noexcept;
|
| 485 |
+
constexpr bool compare_exchange_weak(value_type&, value_type,
|
| 486 |
memory_order, memory_order) const noexcept;
|
| 487 |
+
constexpr bool compare_exchange_strong(value_type&, value_type,
|
| 488 |
memory_order, memory_order) const noexcept;
|
| 489 |
+
constexpr bool compare_exchange_weak(value_type&, value_type,
|
| 490 |
+
memory_order = memory_order::seq_cst) const noexcept;
|
| 491 |
+
constexpr bool compare_exchange_strong(value_type&, value_type,
|
| 492 |
+
memory_order = memory_order::seq_cst) const noexcept;
|
| 493 |
+
|
| 494 |
+
constexpr value_type fetch_add(value_type,
|
| 495 |
+
memory_order = memory_order::seq_cst) const noexcept;
|
| 496 |
+
constexpr value_type fetch_sub(value_type,
|
| 497 |
+
memory_order = memory_order::seq_cst) const noexcept;
|
| 498 |
+
|
| 499 |
+
constexpr value_type fetch_max(value_type,
|
| 500 |
memory_order = memory_order::seq_cst) const noexcept;
|
| 501 |
+
constexpr value_type fetch_min(value_type,
|
| 502 |
+
memory_order = memory_order::seq_cst) const noexcept;
|
| 503 |
+
constexpr value_type fetch_fmaximum(value_type,
|
| 504 |
+
memory_order = memory_order::seq_cst) const noexcept;
|
| 505 |
+
constexpr value_type fetch_fminimum(value_type,
|
| 506 |
+
memory_order = memory_order::seq_cst) const noexcept;
|
| 507 |
+
constexpr value_type fetch_fmaximum_num(value_type,
|
| 508 |
+
memory_order = memory_order::seq_cst) const noexcept;
|
| 509 |
+
constexpr value_type fetch_fminimum_num(value_type,
|
| 510 |
memory_order = memory_order::seq_cst) const noexcept;
|
| 511 |
|
| 512 |
+
constexpr void store_add(value_type, memory_order = memory_order::seq_cst) const noexcept;
|
| 513 |
+
constexpr void store_sub(value_type, memory_order = memory_order::seq_cst) const noexcept;
|
| 514 |
+
constexpr void store_max(value_type, memory_order = memory_order::seq_cst) const noexcept;
|
| 515 |
+
constexpr void store_min(value_type, memory_order = memory_order::seq_cst) const noexcept;
|
| 516 |
+
constexpr void store_fmaximum(value_type,
|
| 517 |
memory_order = memory_order::seq_cst) const noexcept;
|
| 518 |
+
constexpr void store_fminimum(value_type,
|
| 519 |
+
memory_order = memory_order::seq_cst) const noexcept;
|
| 520 |
+
constexpr void store_fmaximum_num(value_type,
|
| 521 |
+
memory_order = memory_order::seq_cst) const noexcept;
|
| 522 |
+
constexpr void store_fminimum_num(value_type,
|
| 523 |
memory_order = memory_order::seq_cst) const noexcept;
|
| 524 |
|
| 525 |
+
constexpr value_type operator+=(value_type) const noexcept;
|
| 526 |
+
constexpr value_type operator-=(value_type) const noexcept;
|
| 527 |
|
| 528 |
+
constexpr void wait(value_type,
|
| 529 |
+
memory_order = memory_order::seq_cst) const noexcept;
|
| 530 |
+
constexpr void notify_one() const noexcept;
|
| 531 |
+
constexpr void notify_all() const noexcept;
|
| 532 |
+
constexpr floating-point-type* address() const noexcept;
|
| 533 |
};
|
| 534 |
}
|
| 535 |
```
|
| 536 |
|
| 537 |
Descriptions are provided below only for members that differ from the
|
| 538 |
primary template.
|
| 539 |
|
| 540 |
The following operations perform arithmetic computations. The
|
| 541 |
correspondence among key, operator, and computation is specified in
|
| 542 |
+
[[atomic.types.int.comp]], except for the keys `max`, `min`, `fmaximum`,
|
| 543 |
+
`fminimum`, `fmaximum_num`, and `fminimum_num`, which are specified
|
| 544 |
+
below.
|
| 545 |
|
| 546 |
``` cpp
|
| 547 |
+
constexpr value_type fetch_key(value_type operand,
|
| 548 |
memory_order order = memory_order::seq_cst) const noexcept;
|
| 549 |
```
|
| 550 |
|
| 551 |
+
*Constraints:* `is_const_v<`*`floating-point-type`*`>` is `false`.
|
| 552 |
+
|
| 553 |
*Effects:* Atomically replaces the value referenced by `*ptr` with the
|
| 554 |
result of the computation applied to the value referenced by `*ptr` and
|
| 555 |
the given operand. Memory is affected according to the value of `order`.
|
| 556 |
These operations are atomic read-modify-write
|
| 557 |
operations [[intro.races]].
|
|
|
|
| 561 |
|
| 562 |
*Remarks:* If the result is not a representable value for its
|
| 563 |
type [[expr.pre]], the result is unspecified, but the operations
|
| 564 |
otherwise have no undefined behavior. Atomic arithmetic operations on
|
| 565 |
*`floating-point-type`* should conform to the
|
| 566 |
+
`std::numeric_limits<value_type>` traits associated with the
|
| 567 |
+
floating-point type [[limits.syn]]. The floating-point
|
| 568 |
environment [[cfenv]] for atomic arithmetic operations on
|
| 569 |
*`floating-point-type`* may be different than the calling thread’s
|
| 570 |
floating-point environment.
|
| 571 |
|
| 572 |
+
- For `fetch_fmaximum` and `fetch_fminimum`, the maximum and minimum
|
| 573 |
+
computation is performed as if by `fmaximum` and `fminimum`,
|
| 574 |
+
respectively, with `*ptr` and the first parameter as the arguments.
|
| 575 |
+
- For `fetch_fmaximum_num` and `fetch_fminimum_num`, the maximum and
|
| 576 |
+
minimum computation is performed as if by `fmaximum_num` and
|
| 577 |
+
`fminimum_num`, respectively, with `*ptr` and the first parameter as
|
| 578 |
+
the arguments.
|
| 579 |
+
- For `fetch_max` and `fetch_min`, the maximum and minimum computation
|
| 580 |
+
is performed as if by `fmaximum_num` and `fminimum_num`, respectively,
|
| 581 |
+
with `*ptr` and the first parameter as the arguments, except that:
|
| 582 |
+
- If both arguments are NaN, an unspecified NaN value is stored at
|
| 583 |
+
`*ptr`.
|
| 584 |
+
- If exactly one argument is a NaN, either the other argument or an
|
| 585 |
+
unspecified NaN value is stored at `*ptr`; it is unspecified which.
|
| 586 |
+
- If the arguments are differently signed zeros, which of these values
|
| 587 |
+
is stored at `*ptr` is unspecified.
|
| 588 |
+
|
| 589 |
+
*Recommended practice:* The implementation of `fetch_max` and
|
| 590 |
+
`fetch_min` should treat negative zero as smaller than positive zero.
|
| 591 |
+
|
| 592 |
``` cpp
|
| 593 |
+
constexpr void store_key(value_type operand,
|
| 594 |
+
memory_order order = memory_order::seq_cst) const noexcept;
|
| 595 |
```
|
| 596 |
|
| 597 |
+
*Preconditions:* `order` is `memory_order::relaxed`,
|
| 598 |
+
`memory_order::release`, or `memory_order::seq_cst`.
|
| 599 |
+
|
| 600 |
+
*Effects:* Atomically replaces the value referenced by `*ptr` with the
|
| 601 |
+
result of the computation applied to the value referenced by `*ptr` and
|
| 602 |
+
the given `operand`. Memory is affected according to the value of
|
| 603 |
+
`order`. These operations are atomic modify-write
|
| 604 |
+
operations [[atomics.order]].
|
| 605 |
+
|
| 606 |
+
*Remarks:* If the result is not a representable value for its
|
| 607 |
+
type [[expr.pre]], the result is unspecified, but the operations
|
| 608 |
+
otherwise have no undefined behavior. Atomic arithmetic operations on
|
| 609 |
+
*`floating-point-type`* should conform to the
|
| 610 |
+
`numeric_limits<`*`floating-point-type`*`>` traits associated with the
|
| 611 |
+
floating-point type [[limits.syn]]. The floating-point
|
| 612 |
+
environment [[cfenv]] for atomic arithmetic operations on
|
| 613 |
+
*`floating-point-type`* may be different than the calling thread’s
|
| 614 |
+
floating-point environment. The arithmetic rules of floating-point
|
| 615 |
+
atomic modify-write operations may be different from operations on
|
| 616 |
+
floating-point types or atomic floating-point types.
|
| 617 |
+
|
| 618 |
+
[*Note 1*: Tree reductions are permitted for atomic modify-write
|
| 619 |
+
operations. — *end note*]
|
| 620 |
+
|
| 621 |
+
- For `store_fmaximum` and `store_fminimum`, the maximum and minimum
|
| 622 |
+
computation is performed as if by `fmaximum` and `fminimum`,
|
| 623 |
+
respectively, with `*ptr` and the first parameter as the arguments.
|
| 624 |
+
- For `store_fmaximum_num` and `store_fminimum_num`, the maximum and
|
| 625 |
+
minimum computation is performed as if by `fmaximum_num `and
|
| 626 |
+
`fminimum_num`, respectively, with `*ptr` and the first parameter as
|
| 627 |
+
the arguments.
|
| 628 |
+
- For `store_max` and `store_min`, the maximum and minimum computation
|
| 629 |
+
is performed as if by `fmaximum_num` and `fminimum_num`, respectively,
|
| 630 |
+
with `*ptr` and the first parameter as the arguments, except that:
|
| 631 |
+
- If both arguments are NaN, an unspecified NaN value is stored at
|
| 632 |
+
`*ptr`.
|
| 633 |
+
- If exactly one argument is a NaN, either the other argument or an
|
| 634 |
+
unspecified NaN value is stored at `*ptr`, it is unspecified which.
|
| 635 |
+
- If the arguments are differently signed zeros, which of these values
|
| 636 |
+
is stored at `*ptr` is unspecified.
|
| 637 |
+
|
| 638 |
+
*Recommended practice:* The implementation of `store_max` and
|
| 639 |
+
`store_min` should treat negative zero as smaller than positive zero.
|
| 640 |
+
|
| 641 |
+
``` cpp
|
| 642 |
+
constexpr value_type operator op=(value_type operand) const noexcept;
|
| 643 |
+
```
|
| 644 |
+
|
| 645 |
+
*Constraints:* `is_const_v<`*`floating-point-type`*`>` is `false`.
|
| 646 |
+
|
| 647 |
*Effects:* Equivalent to:
|
| 648 |
`return fetch_`*`key`*`(operand) `*`op`*` operand;`
|
| 649 |
|
| 650 |
+
#### Specialization for pointers <a id="atomics.ref.pointer">[[atomics.ref.pointer]]</a>
|
| 651 |
+
|
| 652 |
+
There are specializations of the `atomic_ref` class template for all
|
| 653 |
+
pointer-to-object types. For each such type `pointer-type`, the
|
| 654 |
+
specialization `atomic_ref<pointer-type>` provides additional atomic
|
| 655 |
+
operations appropriate to pointer types.
|
| 656 |
+
|
| 657 |
+
The program is ill-formed if `is_always_lock_free` is `false` and
|
| 658 |
+
`is_volatile_v<pointer-type>` is `true`.
|
| 659 |
|
| 660 |
``` cpp
|
| 661 |
namespace std {
|
| 662 |
+
template<> struct atomic_ref<pointer-type> {
|
| 663 |
private:
|
| 664 |
+
pointer-type* ptr; // exposition only
|
| 665 |
|
| 666 |
public:
|
| 667 |
+
using value_type = remove_cv_t<pointer-type>;
|
| 668 |
using difference_type = ptrdiff_t;
|
| 669 |
static constexpr size_t required_alignment = implementation-defined // required alignment for atomic_ref type's operations;
|
| 670 |
|
| 671 |
static constexpr bool is_always_lock_free = implementation-defined // whether a given atomic_ref type's operations are always lock free;
|
| 672 |
bool is_lock_free() const noexcept;
|
| 673 |
|
| 674 |
+
constexpr explicit atomic_ref(pointer-type&);
|
| 675 |
+
constexpr atomic_ref(const atomic_ref&) noexcept;
|
| 676 |
atomic_ref& operator=(const atomic_ref&) = delete;
|
| 677 |
|
| 678 |
+
constexpr void store(value_type, memory_order = memory_order::seq_cst) const noexcept;
|
| 679 |
+
constexpr value_type operator=(value_type) const noexcept;
|
| 680 |
+
constexpr value_type load(memory_order = memory_order::seq_cst) const noexcept;
|
| 681 |
+
constexpr operator value_type() const noexcept;
|
| 682 |
|
| 683 |
+
constexpr value_type exchange(value_type,
|
| 684 |
+
memory_order = memory_order::seq_cst) const noexcept;
|
| 685 |
+
constexpr bool compare_exchange_weak(value_type&, value_type,
|
| 686 |
memory_order, memory_order) const noexcept;
|
| 687 |
+
constexpr bool compare_exchange_strong(value_type&, value_type,
|
| 688 |
memory_order, memory_order) const noexcept;
|
| 689 |
+
constexpr bool compare_exchange_weak(value_type&, value_type,
|
| 690 |
+
memory_order = memory_order::seq_cst) const noexcept;
|
| 691 |
+
constexpr bool compare_exchange_strong(value_type&, value_type,
|
| 692 |
+
memory_order = memory_order::seq_cst) const noexcept;
|
| 693 |
+
|
| 694 |
+
constexpr value_type fetch_add(difference_type,
|
| 695 |
+
memory_order = memory_order::seq_cst) const noexcept;
|
| 696 |
+
constexpr value_type fetch_sub(difference_type,
|
| 697 |
memory_order = memory_order::seq_cst) const noexcept;
|
| 698 |
+
constexpr value_type fetch_max(value_type,
|
| 699 |
+
memory_order = memory_order::seq_cst) const noexcept;
|
| 700 |
+
constexpr value_type fetch_min(value_type,
|
| 701 |
memory_order = memory_order::seq_cst) const noexcept;
|
| 702 |
|
| 703 |
+
constexpr void store_add(difference_type,
|
| 704 |
+
memory_order = memory_order::seq_cst) const noexcept;
|
| 705 |
+
constexpr void store_sub(difference_type,
|
| 706 |
+
memory_order = memory_order::seq_cst) const noexcept;
|
| 707 |
+
constexpr void store_max(value_type,
|
| 708 |
+
memory_order = memory_order::seq_cst) const noexcept;
|
| 709 |
+
constexpr void store_min(value_type,
|
| 710 |
+
memory_order = memory_order::seq_cst) const noexcept;
|
| 711 |
|
| 712 |
+
constexpr value_type operator++(int) const noexcept;
|
| 713 |
+
constexpr value_type operator--(int) const noexcept;
|
| 714 |
+
constexpr value_type operator++() const noexcept;
|
| 715 |
+
constexpr value_type operator--() const noexcept;
|
| 716 |
+
constexpr value_type operator+=(difference_type) const noexcept;
|
| 717 |
+
constexpr value_type operator-=(difference_type) const noexcept;
|
| 718 |
|
| 719 |
+
constexpr void wait(value_type, memory_order = memory_order::seq_cst) const noexcept;
|
| 720 |
+
constexpr void notify_one() const noexcept;
|
| 721 |
+
constexpr void notify_all() const noexcept;
|
| 722 |
+
constexpr pointer-type* address() const noexcept;
|
| 723 |
};
|
| 724 |
}
|
| 725 |
```
|
| 726 |
|
| 727 |
Descriptions are provided below only for members that differ from the
|
|
|
|
| 730 |
The following operations perform arithmetic computations. The
|
| 731 |
correspondence among key, operator, and computation is specified in
|
| 732 |
[[atomic.types.pointer.comp]].
|
| 733 |
|
| 734 |
``` cpp
|
| 735 |
+
constexpr value_type fetch_key(\seeabovenc operand,
|
| 736 |
+
memory_order order = memory_order::seq_cst) const noexcept;
|
| 737 |
```
|
| 738 |
|
| 739 |
+
*Constraints:* `is_const_v<`*`pointer-type`*`>` is `false`.
|
| 740 |
+
|
| 741 |
+
*Mandates:* `remove_pointer_t<`*`pointer-type`*`>` is a complete object
|
| 742 |
+
type.
|
| 743 |
|
| 744 |
*Effects:* Atomically replaces the value referenced by `*ptr` with the
|
| 745 |
result of the computation applied to the value referenced by `*ptr` and
|
| 746 |
the given operand. Memory is affected according to the value of `order`.
|
| 747 |
These operations are atomic read-modify-write
|
|
|
|
| 751 |
the effects.
|
| 752 |
|
| 753 |
*Remarks:* The result may be an undefined address, but the operations
|
| 754 |
otherwise have no undefined behavior.
|
| 755 |
|
| 756 |
+
For `fetch_max` and `fetch_min`, the maximum and minimum computation is
|
| 757 |
+
performed as if by `max` and `min` algorithms [[alg.min.max]],
|
| 758 |
+
respectively, with the object value and the first parameter as the
|
| 759 |
+
arguments.
|
| 760 |
+
|
| 761 |
+
[*Note 1*: If the pointers point to different complete objects (or
|
| 762 |
+
subobjects thereof), the `<` operator does not establish a strict weak
|
| 763 |
+
ordering ([[cpp17.lessthancomparable]], [[expr.rel]]). — *end note*]
|
| 764 |
+
|
| 765 |
``` cpp
|
| 766 |
+
constexpr void store_key(\seeabovenc operand,
|
| 767 |
+
memory_order order = memory_order::seq_cst) const noexcept;
|
| 768 |
```
|
| 769 |
|
| 770 |
+
*Mandates:* `remove_pointer_t<`*`pointer-type`*`>` is a complete object
|
| 771 |
+
type.
|
| 772 |
+
|
| 773 |
+
*Preconditions:* `order` is `memory_order::relaxed`,
|
| 774 |
+
`memory_order::release`, or `memory_order::seq_cst`.
|
| 775 |
+
|
| 776 |
+
*Effects:* Atomically replaces the value referenced by `*ptr` with the
|
| 777 |
+
result of the computation applied to the value referenced by `*ptr` and
|
| 778 |
+
the given `operand`. Memory is affected according to the value of
|
| 779 |
+
`order`. These operations are atomic modify-write
|
| 780 |
+
operations [[atomics.order]].
|
| 781 |
+
|
| 782 |
+
*Remarks:* The result may be an undefined address, but the operations
|
| 783 |
+
otherwise have no undefined behavior. For `store_max` and `store_min`,
|
| 784 |
+
the `maximum` and `minimum` computation is performed as if by `max` and
|
| 785 |
+
`min` algorithms [[alg.min.max]], respectively, with `*ptr` and the
|
| 786 |
+
first parameter as the arguments.
|
| 787 |
+
|
| 788 |
+
[*Note 2*: If the pointers point to different complete objects (or
|
| 789 |
+
subobjects thereof), the `<` operator does not establish a strict weak
|
| 790 |
+
ordering ([[cpp17.lessthancomparable]], [[expr.rel]]). — *end note*]
|
| 791 |
+
|
| 792 |
+
``` cpp
|
| 793 |
+
constexpr value_type operator op=(difference_type operand) const noexcept;
|
| 794 |
+
```
|
| 795 |
+
|
| 796 |
+
*Constraints:* `is_const_v<`*`pointer-type`*`>` is `false`.
|
| 797 |
+
|
| 798 |
*Effects:* Equivalent to:
|
| 799 |
`return fetch_`*`key`*`(operand) `*`op`*` operand;`
|
| 800 |
|
| 801 |
#### Member operators common to integers and pointers to objects <a id="atomics.ref.memop">[[atomics.ref.memop]]</a>
|
| 802 |
|
| 803 |
+
Let `referred-type` be `pointer-type` for the specializations in
|
| 804 |
+
[[atomics.ref.pointer]] and be `integral-type` for the specializations
|
| 805 |
+
in [[atomics.ref.int]].
|
| 806 |
+
|
| 807 |
``` cpp
|
| 808 |
+
constexpr value_type operator++(int) const noexcept;
|
| 809 |
```
|
| 810 |
|
| 811 |
+
*Constraints:* `is_const_v<`*`referred-type`*`>` is `false`.
|
| 812 |
+
|
| 813 |
*Effects:* Equivalent to: `return fetch_add(1);`
|
| 814 |
|
| 815 |
``` cpp
|
| 816 |
+
constexpr value_type operator--(int) const noexcept;
|
| 817 |
```
|
| 818 |
|
| 819 |
+
*Constraints:* `is_const_v<`*`referred-type`*`>` is `false`.
|
| 820 |
+
|
| 821 |
*Effects:* Equivalent to: `return fetch_sub(1);`
|
| 822 |
|
| 823 |
``` cpp
|
| 824 |
+
constexpr value_type operator++() const noexcept;
|
| 825 |
```
|
| 826 |
|
| 827 |
+
*Constraints:* `is_const_v<`*`referred-type`*`>` is `false`.
|
| 828 |
+
|
| 829 |
*Effects:* Equivalent to: `return fetch_add(1) + 1;`
|
| 830 |
|
| 831 |
``` cpp
|
| 832 |
+
constexpr value_type operator--() const noexcept;
|
| 833 |
```
|
| 834 |
|
| 835 |
+
*Constraints:* `is_const_v<`*`referred-type`*`>` is `false`.
|
| 836 |
+
|
| 837 |
*Effects:* Equivalent to: `return fetch_sub(1) - 1;`
|
| 838 |
|