Skip to content

Commit eda1581

Browse files
authored
Merge 2019-11 LWG Motion 20
P0883R2 Fixing Atomic Initialization
2 parents 9124aa5 + af48b06 commit eda1581

File tree

3 files changed

+109
-87
lines changed

3 files changed

+109
-87
lines changed

source/atomics.tex

Lines changed: 27 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -56,18 +56,11 @@
5656
// \ref{atomics.types.pointer}, partial specialization for pointers
5757
template<class T> struct atomic<T*>;
5858

59-
// \ref{atomics.types.operations}, initialization
60-
#define ATOMIC_VAR_INIT(value) @\seebelow@
61-
6259
// \ref{atomics.nonmembers}, non-member functions
6360
template<class T>
6461
bool atomic_is_lock_free(const volatile atomic<T>*) noexcept;
6562
template<class T>
6663
bool atomic_is_lock_free(const atomic<T>*) noexcept;
67-
template<class T>
68-
void atomic_init(volatile atomic<T>*, typename atomic<T>::value_type) noexcept;
69-
template<class T>
70-
void atomic_init(atomic<T>*, typename atomic<T>::value_type) noexcept;
7164
template<class T>
7265
void atomic_store(volatile atomic<T>*, typename atomic<T>::value_type) noexcept;
7366
template<class T>
@@ -261,8 +254,6 @@
261254
// \ref{atomics.flag}, flag type and operations
262255
struct atomic_flag;
263256

264-
#define ATOMIC_FLAG_INIT @\seebelow@
265-
266257
bool atomic_flag_test(const volatile atomic_flag*) noexcept;
267258
bool atomic_flag_test(const atomic_flag*) noexcept;
268259
bool atomic_flag_test_explicit(const volatile atomic_flag*, memory_order) noexcept;
@@ -1551,7 +1542,8 @@
15511542
bool is_lock_free() const volatile noexcept;
15521543
bool is_lock_free() const noexcept;
15531544

1554-
atomic() noexcept = default;
1545+
// \ref{atomics.types.operations}, operations on atomic types
1546+
constexpr atomic() noexcept(is_nothrow_default_constructible_v<T>);
15551547
constexpr atomic(T) noexcept;
15561548
atomic(const atomic&) = delete;
15571549
atomic& operator=(const atomic&) = delete;
@@ -1625,44 +1617,23 @@
16251617
operations on non-volatile objects become volatile.
16261618
\end{note}
16271619

1628-
\indexlibraryglobal{ATOMIC_VAR_INIT}%
1629-
\begin{itemdecl}
1630-
#define ATOMIC_VAR_INIT(value) @\seebelow@
1631-
\end{itemdecl}
1632-
1633-
\begin{itemdescr}
1634-
\pnum
1635-
The macro expands to a token sequence suitable for
1636-
constant initialization of
1637-
an atomic variable of static storage duration of a type that is
1638-
initialization-compatible with \tcode{value}.
1639-
\begin{note}
1640-
This operation may need to initialize locks.
1641-
\end{note}
1642-
Concurrent access to the variable being initialized, even via an atomic operation,
1643-
constitutes a data race.
1644-
\begin{example}
1645-
\begin{codeblock}
1646-
atomic<int> v = ATOMIC_VAR_INIT(5);
1647-
\end{codeblock}
1648-
\end{example}
1649-
\end{itemdescr}
1650-
16511620
\indexlibraryctor{atomic}%
16521621
\indexlibraryctor{atomic<T*>}%
16531622
\indexlibrary{\idxcode{atomic<\placeholder{integral}>}!constructor}%
16541623
\indexlibrary{\idxcode{atomic<\placeholder{floating-point}>}!constructor}%
16551624
\begin{itemdecl}
1656-
atomic() noexcept = default;
1625+
constexpr atomic() noexcept(is_nothrow_default_constructible_v<T>);
16571626
\end{itemdecl}
16581627

16591628
\begin{itemdescr}
1629+
\pnum
1630+
\mandates
1631+
\tcode{is_default_constructible_v<T>} is \tcode{true}.
1632+
16601633
\pnum
16611634
\effects
1662-
Leaves the atomic object in an uninitialized state.
1663-
\begin{note}
1664-
These semantics ensure compatibility with C.
1665-
\end{note}
1635+
Initializes the atomic object with the value of \tcode{T()}.
1636+
Initialization is not an atomic operation\iref{intro.multithread}.
16661637
\end{itemdescr}
16671638

16681639
\indexlibraryctor{atomic}%
@@ -2118,7 +2089,7 @@
21182089
bool is_lock_free() const volatile noexcept;
21192090
bool is_lock_free() const noexcept;
21202091

2121-
atomic() noexcept = default;
2092+
constexpr atomic() noexcept;
21222093
constexpr atomic(@\placeholdernc{integral}@) noexcept;
21232094
atomic(const atomic&) = delete;
21242095
atomic& operator=(const atomic&) = delete;
@@ -2195,8 +2166,8 @@
21952166
\pnum
21962167
The atomic integral specializations
21972168
are standard-layout structs.
2198-
They each have a trivial default constructor
2199-
and a trivial destructor.
2169+
They each have
2170+
a trivial destructor.
22002171

22012172
\pnum
22022173
Descriptions are provided below only for members that differ from the primary template.
@@ -2318,7 +2289,7 @@
23182289
bool is_lock_free() const volatile noexcept;
23192290
bool is_lock_free() const noexcept;
23202291

2321-
atomic() noexcept = default;
2292+
constexpr atomic() noexcept;
23222293
constexpr atomic(@\placeholder{floating-point}@) noexcept;
23232294
atomic(const atomic&) = delete;
23242295
atomic& operator=(const atomic&) = delete;
@@ -2381,8 +2352,8 @@
23812352
\pnum
23822353
The atomic floating-point specializations
23832354
are standard-layout structs.
2384-
They each have a trivial default constructor
2385-
and a trivial destructor.
2355+
They each have
2356+
a trivial destructor.
23862357

23872358
\pnum
23882359
Descriptions are provided below only for members that differ from the primary template.
@@ -2467,7 +2438,7 @@
24672438
bool is_lock_free() const volatile noexcept;
24682439
bool is_lock_free() const noexcept;
24692440

2470-
atomic() noexcept = default;
2441+
constexpr atomic() noexcept;
24712442
constexpr atomic(T*) noexcept;
24722443
atomic(const atomic&) = delete;
24732444
atomic& operator=(const atomic&) = delete;
@@ -2529,7 +2500,7 @@
25292500
\pnum
25302501
There is a partial specialization of the \tcode{atomic} class template for pointers.
25312502
Specializations of this partial specialization are standard-layout structs.
2532-
They each have a trivial default constructor and a trivial destructor.
2503+
They each have a trivial destructor.
25332504

25342505
\pnum
25352506
Descriptions are provided below only for members that differ from the primary template.
@@ -2717,7 +2688,7 @@
27172688
void notify_one() noexcept;
27182689
void notify_all() noexcept;
27192690

2720-
constexpr atomic() noexcept = default;
2691+
constexpr atomic() noexcept;
27212692
atomic(shared_ptr<T> desired) noexcept;
27222693
atomic(const atomic&) = delete;
27232694
void operator=(const atomic&) = delete;
@@ -2731,7 +2702,7 @@
27312702

27322703
\indexlibraryctor{atomic<shared_ptr<T>>}%
27332704
\begin{itemdecl}
2734-
constexpr atomic() noexcept = default;
2705+
constexpr atomic() noexcept;
27352706
\end{itemdecl}
27362707

27372708
\begin{itemdescr}
@@ -3025,7 +2996,7 @@
30252996
void notify_one() noexcept;
30262997
void notify_all() noexcept;
30272998

3028-
constexpr atomic() noexcept = default;
2999+
constexpr atomic() noexcept;
30293000
atomic(weak_ptr<T> desired) noexcept;
30303001
atomic(const atomic&) = delete;
30313002
void operator=(const atomic&) = delete;
@@ -3039,7 +3010,7 @@
30393010

30403011
\indexlibraryctor{atomic<weak_ptr<T>>}%
30413012
\begin{itemdecl}
3042-
constexpr atomic() noexcept = default;
3013+
constexpr atomic() noexcept;
30433014
\end{itemdecl}
30443015

30453016
\begin{itemdescr}
@@ -3316,29 +3287,6 @@
33163287
passed to the member function call.
33173288
If no such member function exists, the program is ill-formed.
33183289

3319-
\indexlibraryglobal{atomic_init}%
3320-
\begin{itemdecl}
3321-
template<class T>
3322-
void atomic_init(volatile atomic<T>* object, typename atomic<T>::value_type desired) noexcept;
3323-
template<class T>
3324-
void atomic_init(atomic<T>* object, typename atomic<T>::value_type desired) noexcept;
3325-
\end{itemdecl}
3326-
3327-
\begin{itemdescr}
3328-
\pnum
3329-
\effects
3330-
Non-atomically
3331-
initializes \tcode{*object} with value \tcode{desired}. This function shall only be applied
3332-
to objects that have been default constructed, and then only once.
3333-
\begin{note}
3334-
These semantics ensure compatibility with C.
3335-
\end{note}
3336-
\begin{note}
3337-
Concurrent access from another thread, even via an atomic operation, constitutes
3338-
a data race.
3339-
\end{note}
3340-
\end{itemdescr}
3341-
33423290
\pnum
33433291
\begin{note}
33443292
The non-member functions enable programmers to write code that can be
@@ -3350,7 +3298,7 @@
33503298
\begin{codeblock}
33513299
namespace std {
33523300
struct atomic_flag {
3353-
atomic_flag() noexcept = default;
3301+
constexpr atomic_flag() noexcept;
33543302
atomic_flag(const atomic_flag&) = delete;
33553303
atomic_flag& operator=(const atomic_flag&) = delete;
33563304
atomic_flag& operator=(const atomic_flag&) volatile = delete;
@@ -3384,25 +3332,17 @@
33843332

33853333
\pnum
33863334
The \tcode{atomic_flag} type is a standard-layout struct.
3387-
It has a trivial default constructor and a trivial destructor.
3335+
It has a trivial destructor.
33883336

3389-
\indexlibraryglobal{ATOMIC_FLAG_INIT}%
3337+
\indexlibraryctor{atomic_flag}%
33903338
\begin{itemdecl}
3391-
#define ATOMIC_FLAG_INIT @\seebelow@
3339+
constexpr atomic_flag::atomic_flag() noexcept;
33923340
\end{itemdecl}
33933341

33943342
\begin{itemdescr}
33953343
\pnum
3396-
\remarks
3397-
The macro \tcode{ATOMIC_FLAG_INIT} shall be defined in such a way that it can be used to initialize an object of type \tcode{atomic_flag} to the
3398-
clear state. The macro can be used in the form:
3399-
\begin{codeblock}
3400-
atomic_flag guard = ATOMIC_FLAG_INIT;
3401-
\end{codeblock}
3402-
It is unspecified whether the macro can be used in other initialization contexts.
3403-
For a complete static-duration object, that initialization shall be static.
3404-
Unless initialized with \tcode{ATOMIC_FLAG_INIT}, it is unspecified whether an
3405-
\tcode{atomic_flag} object has an initial state of set or clear.
3344+
\effects
3345+
Initializes \tcode{*this} to the clear state.
34063346
\end{itemdescr}
34073347

34083348
\indexlibraryglobal{atomic_flag_test}%

source/future.tex

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2487,3 +2487,84 @@
24872487
UTF-16 occurs.
24882488
\end{example}
24892489
\end{itemdescr}
2490+
2491+
\rSec1[depr.atomics]{Deprecated atomic initialization}
2492+
2493+
\pnum
2494+
The header \libheaderref{atomics} has the following additions.
2495+
2496+
\begin{codeblock}
2497+
namespace std {
2498+
template<class T>
2499+
void atomic_init(volatile atomic<T>*, typename atomic<T>::value_type) noexcept;
2500+
template<class T>
2501+
void atomic_init(atomic<T>*, typename atomic<T>::value_type) noexcept;
2502+
2503+
#define ATOMIC_VAR_INIT(value) @\seebelow@
2504+
2505+
#define ATOMIC_FLAG_INIT @\seebelow@
2506+
}
2507+
\end{codeblock}
2508+
2509+
\rSec2[depr.atomics.nonmembers]{Non-member functions}
2510+
2511+
\indexlibraryglobal{atomic_init}%
2512+
\begin{itemdecl}
2513+
template<class T>
2514+
void atomic_init(volatile atomic<T>* object, typename atomic<T>::value_type desired) noexcept;
2515+
template<class T>
2516+
void atomic_init(atomic<T>* object, typename atomic<T>::value_type desired) noexcept;
2517+
\end{itemdecl}
2518+
2519+
\begin{itemdescr}
2520+
\pnum
2521+
\effects
2522+
Equivalent to: \tcode{atomic_store_explicit(object, desired, memory_order_relaxed);}
2523+
\end{itemdescr}
2524+
2525+
\rSec2[depr.atomics.types.operations]{Operations on atomic types}
2526+
2527+
\indexlibraryglobal{ATOMIC_VAR_INIT}%
2528+
\begin{itemdecl}
2529+
#define ATOMIC_VAR_INIT(value) @\seebelow@
2530+
\end{itemdecl}
2531+
2532+
\begin{itemdescr}
2533+
\pnum
2534+
The macro expands to a token sequence suitable for constant initialization of
2535+
an atomic variable of static storage duration of a type that
2536+
is initialization-compatible with \tcode{value}.
2537+
\begin{note}
2538+
This operation may need to initialize locks.
2539+
\end{note}
2540+
Concurrent access to the variable being initialized,
2541+
even via an atomic operation,
2542+
constitutes a data race.
2543+
\begin{example}
2544+
\begin{codeblock}
2545+
atomic<int> v = ATOMIC_VAR_INIT(5);
2546+
\end{codeblock}
2547+
\end{example}
2548+
\end{itemdescr}
2549+
2550+
\rSec2[depr.atomics.flag]{Flag type and operations}
2551+
2552+
\indexlibraryglobal{ATOMIC_FLAG_INIT}%
2553+
\begin{itemdecl}
2554+
#define ATOMIC_FLAG_INIT @\seebelow@
2555+
\end{itemdecl}
2556+
2557+
\begin{itemdescr}
2558+
\pnum
2559+
\remarks
2560+
The macro \tcode{ATOMIC_FLAG_INIT} shall be defined in such a way that
2561+
it can be used to initialize an object of type \tcode{atomic_flag}
2562+
to the clear state.
2563+
The macro can be used in the form:
2564+
\begin{codeblock}
2565+
atomic_flag guard = ATOMIC_FLAG_INIT;
2566+
\end{codeblock}
2567+
It is unspecified whether the macro can be used
2568+
in other initialization contexts.
2569+
For a complete static-duration object, that initialization shall be static.
2570+
\end{itemdescr}

source/support.tex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,7 @@
563563
#define @\defnlibxname{cpp_lib_atomic_lock_free_type_aliases}@ 201907L // also in \libheader{atomic}
564564
#define @\defnlibxname{cpp_lib_atomic_ref}@ 201806L // also in \libheader{atomic}
565565
#define @\defnlibxname{cpp_lib_atomic_shared_ptr}@ 201711L // also in \libheader{memory}
566+
#define @\defnlibxname{cpp_lib_atomic_value_initialization}@ 201911L // also in \libheader{atomic}, \libheader{memory}
566567
#define @\defnlibxname{cpp_lib_atomic_wait}@ 201907L // also in \libheader{atomic}
567568
#define @\defnlibxname{cpp_lib_barrier}@ 201907L // also in \libheader{barrier}
568569
#define @\defnlibxname{cpp_lib_bit_cast}@ 201806L // also in \libheader{bit}

0 commit comments

Comments
 (0)