Skip to content

Commit

Permalink
P0883R2 Fixing Atomic Initialization
Browse files Browse the repository at this point in the history
[depr.atomics] Added additional deprecated sections.

Also fixes NB CA 353, US 351, DE 18, and RU 6 (C++20 CD), and LWG2334.
  • Loading branch information
Dawn Perchik authored and zygoloid committed Nov 24, 2019
1 parent 9124aa5 commit bbb4626
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 87 deletions.
113 changes: 26 additions & 87 deletions source/atomics.tex
Expand Up @@ -56,18 +56,11 @@
// \ref{atomics.types.pointer}, partial specialization for pointers
template<class T> struct atomic<T*>;

// \ref{atomics.types.operations}, initialization
#define ATOMIC_VAR_INIT(value) @\seebelow@

// \ref{atomics.nonmembers}, non-member functions
template<class T>
bool atomic_is_lock_free(const volatile atomic<T>*) noexcept;
template<class T>
bool atomic_is_lock_free(const atomic<T>*) noexcept;
template<class T>
void atomic_init(volatile atomic<T>*, typename atomic<T>::value_type) noexcept;
template<class T>
void atomic_init(atomic<T>*, typename atomic<T>::value_type) noexcept;
template<class T>
void atomic_store(volatile atomic<T>*, typename atomic<T>::value_type) noexcept;
template<class T>
Expand Down Expand Up @@ -261,8 +254,6 @@
// \ref{atomics.flag}, flag type and operations
struct atomic_flag;

#define ATOMIC_FLAG_INIT @\seebelow@

bool atomic_flag_test(const volatile atomic_flag*) noexcept;
bool atomic_flag_test(const atomic_flag*) noexcept;
bool atomic_flag_test_explicit(const volatile atomic_flag*, memory_order) noexcept;
Expand Down Expand Up @@ -1551,7 +1542,7 @@
bool is_lock_free() const volatile noexcept;
bool is_lock_free() const noexcept;

atomic() noexcept = default;
constexpr atomic() noexcept(is_nothrow_default_constructible_v<T>);
constexpr atomic(T) noexcept;
atomic(const atomic&) = delete;
atomic& operator=(const atomic&) = delete;
Expand Down Expand Up @@ -1625,44 +1616,23 @@
operations on non-volatile objects become volatile.
\end{note}

\indexlibraryglobal{ATOMIC_VAR_INIT}%
\begin{itemdecl}
#define ATOMIC_VAR_INIT(value) @\seebelow@
\end{itemdecl}

\begin{itemdescr}
\pnum
The macro expands to a token sequence suitable for
constant initialization of
an atomic variable of static storage duration of a type that is
initialization-compatible with \tcode{value}.
\begin{note}
This operation may need to initialize locks.
\end{note}
Concurrent access to the variable being initialized, even via an atomic operation,
constitutes a data race.
\begin{example}
\begin{codeblock}
atomic<int> v = ATOMIC_VAR_INIT(5);
\end{codeblock}
\end{example}
\end{itemdescr}

\indexlibraryctor{atomic}%
\indexlibraryctor{atomic<T*>}%
\indexlibrary{\idxcode{atomic<\placeholder{integral}>}!constructor}%
\indexlibrary{\idxcode{atomic<\placeholder{floating-point}>}!constructor}%
\begin{itemdecl}
atomic() noexcept = default;
constexpr atomic() noexcept(is_nothrow_default_constructible_v<T>);
\end{itemdecl}

\begin{itemdescr}
\pnum
\mandates
\tcode{is_default_constructible_v<T>} is \tcode{true}.

\pnum
\effects
Leaves the atomic object in an uninitialized state.
\begin{note}
These semantics ensure compatibility with C.
\end{note}
Initializes the atomic object with the value of \tcode{T()}.
Initialization is not an atomic operation\iref{intro.multithread}.
\end{itemdescr}

\indexlibraryctor{atomic}%
Expand Down Expand Up @@ -2118,7 +2088,7 @@
bool is_lock_free() const volatile noexcept;
bool is_lock_free() const noexcept;

atomic() noexcept = default;
constexpr atomic() noexcept;
constexpr atomic(@\placeholdernc{integral}@) noexcept;
atomic(const atomic&) = delete;
atomic& operator=(const atomic&) = delete;
Expand Down Expand Up @@ -2195,8 +2165,8 @@
\pnum
The atomic integral specializations
are standard-layout structs.
They each have a trivial default constructor
and a trivial destructor.
They each have
a trivial destructor.

\pnum
Descriptions are provided below only for members that differ from the primary template.
Expand Down Expand Up @@ -2318,7 +2288,7 @@
bool is_lock_free() const volatile noexcept;
bool is_lock_free() const noexcept;

atomic() noexcept = default;
constexpr atomic() noexcept;
constexpr atomic(@\placeholder{floating-point}@) noexcept;
atomic(const atomic&) = delete;
atomic& operator=(const atomic&) = delete;
Expand Down Expand Up @@ -2381,8 +2351,8 @@
\pnum
The atomic floating-point specializations
are standard-layout structs.
They each have a trivial default constructor
and a trivial destructor.
They each have
a trivial destructor.

\pnum
Descriptions are provided below only for members that differ from the primary template.
Expand Down Expand Up @@ -2467,7 +2437,7 @@
bool is_lock_free() const volatile noexcept;
bool is_lock_free() const noexcept;

atomic() noexcept = default;
constexpr atomic() noexcept;
constexpr atomic(T*) noexcept;
atomic(const atomic&) = delete;
atomic& operator=(const atomic&) = delete;
Expand Down Expand Up @@ -2529,7 +2499,7 @@
\pnum
There is a partial specialization of the \tcode{atomic} class template for pointers.
Specializations of this partial specialization are standard-layout structs.
They each have a trivial default constructor and a trivial destructor.
They each have a trivial destructor.

\pnum
Descriptions are provided below only for members that differ from the primary template.
Expand Down Expand Up @@ -2717,7 +2687,7 @@
void notify_one() noexcept;
void notify_all() noexcept;

constexpr atomic() noexcept = default;
constexpr atomic() noexcept;
atomic(shared_ptr<T> desired) noexcept;
atomic(const atomic&) = delete;
void operator=(const atomic&) = delete;
Expand All @@ -2731,7 +2701,7 @@

\indexlibraryctor{atomic<shared_ptr<T>>}%
\begin{itemdecl}
constexpr atomic() noexcept = default;
constexpr atomic() noexcept;
\end{itemdecl}

\begin{itemdescr}
Expand Down Expand Up @@ -3025,7 +2995,7 @@
void notify_one() noexcept;
void notify_all() noexcept;

constexpr atomic() noexcept = default;
constexpr atomic() noexcept;
atomic(weak_ptr<T> desired) noexcept;
atomic(const atomic&) = delete;
void operator=(const atomic&) = delete;
Expand All @@ -3039,7 +3009,7 @@

\indexlibraryctor{atomic<weak_ptr<T>>}%
\begin{itemdecl}
constexpr atomic() noexcept = default;
constexpr atomic() noexcept;
\end{itemdecl}

\begin{itemdescr}
Expand Down Expand Up @@ -3316,29 +3286,6 @@
passed to the member function call.
If no such member function exists, the program is ill-formed.

\indexlibraryglobal{atomic_init}%
\begin{itemdecl}
template<class T>
void atomic_init(volatile atomic<T>* object, typename atomic<T>::value_type desired) noexcept;
template<class T>
void atomic_init(atomic<T>* object, typename atomic<T>::value_type desired) noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Non-atomically
initializes \tcode{*object} with value \tcode{desired}. This function shall only be applied
to objects that have been default constructed, and then only once.
\begin{note}
These semantics ensure compatibility with C.
\end{note}
\begin{note}
Concurrent access from another thread, even via an atomic operation, constitutes
a data race.
\end{note}
\end{itemdescr}

\pnum
\begin{note}
The non-member functions enable programmers to write code that can be
Expand All @@ -3350,7 +3297,7 @@
\begin{codeblock}
namespace std {
struct atomic_flag {
atomic_flag() noexcept = default;
constexpr atomic_flag() noexcept;
atomic_flag(const atomic_flag&) = delete;
atomic_flag& operator=(const atomic_flag&) = delete;
atomic_flag& operator=(const atomic_flag&) volatile = delete;
Expand Down Expand Up @@ -3384,25 +3331,17 @@

\pnum
The \tcode{atomic_flag} type is a standard-layout struct.
It has a trivial default constructor and a trivial destructor.
It has a trivial destructor.

\indexlibraryglobal{ATOMIC_FLAG_INIT}%
\indexlibraryctor{atomic_flag}%
\begin{itemdecl}
#define ATOMIC_FLAG_INIT @\seebelow@
constexpr atomic_flag::atomic_flag() noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\remarks
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
clear state. The macro can be used in the form:
\begin{codeblock}
atomic_flag guard = ATOMIC_FLAG_INIT;
\end{codeblock}
It is unspecified whether the macro can be used in other initialization contexts.
For a complete static-duration object, that initialization shall be static.
Unless initialized with \tcode{ATOMIC_FLAG_INIT}, it is unspecified whether an
\tcode{atomic_flag} object has an initial state of set or clear.
\effects
Initializes \tcode{*this} to the clear state.
\end{itemdescr}

\indexlibraryglobal{atomic_flag_test}%
Expand Down
81 changes: 81 additions & 0 deletions source/future.tex
Expand Up @@ -2487,3 +2487,84 @@
UTF-16 occurs.
\end{example}
\end{itemdescr}

\rSec1[depr.atomics]{Deprecated atomic initialization}

\pnum
The header \libheaderref{atomics} has the following additions.

\begin{codeblock}
namespace std {
template<class T>
void atomic_init(volatile atomic<T>*, typename atomic<T>::value_type) noexcept;
template<class T>
void atomic_init(atomic<T>*, typename atomic<T>::value_type) noexcept;

#define ATOMIC_VAR_INIT(value) @\seebelow@

#define ATOMIC_FLAG_INIT @\seebelow@
}
\end{codeblock}

\rSec2[depr.atomics.nonmembers]{Non-member functions}

\indexlibraryglobal{atomic_init}%
\begin{itemdecl}
template<class T>
void atomic_init(volatile atomic<T>* object, typename atomic<T>::value_type desired) noexcept;
template<class T>
void atomic_init(atomic<T>* object, typename atomic<T>::value_type desired) noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to: \tcode{atomic_store_explicit(object, desired, memory_order_relaxed);}
\end{itemdescr}

\rSec2[depr.atomics.types.operations]{Operations on atomic types}

\indexlibraryglobal{ATOMIC_VAR_INIT}%
\begin{itemdecl}
#define ATOMIC_VAR_INIT(value) @\seebelow@
\end{itemdecl}

\begin{itemdescr}
\pnum
The macro expands to a token sequence suitable for constant initialization of
an atomic variable of static storage duration of a type that
is initialization-compatible with \tcode{value}.
\begin{note}
This operation may need to initialize locks.
\end{note}
Concurrent access to the variable being initialized,
even via an atomic operation,
constitutes a data race.
\begin{example}
\begin{codeblock}
atomic<int> v = ATOMIC_VAR_INIT(5);
\end{codeblock}
\end{example}
\end{itemdescr}

\rSec2[depr.atomics.flag]{Flag type and operations}

\indexlibraryglobal{ATOMIC_FLAG_INIT}%
\begin{itemdecl}
#define ATOMIC_FLAG_INIT @\seebelow@
\end{itemdecl}

\begin{itemdescr}
\pnum
\remarks
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 clear state.
The macro can be used in the form:
\begin{codeblock}
atomic_flag guard = ATOMIC_FLAG_INIT;
\end{codeblock}
It is unspecified whether the macro can be used
in other initialization contexts.
For a complete static-duration object, that initialization shall be static.
\end{itemdescr}
1 change: 1 addition & 0 deletions source/support.tex
Expand Up @@ -563,6 +563,7 @@
#define @\defnlibxname{cpp_lib_atomic_lock_free_type_aliases}@ 201907L // also in \libheader{atomic}
#define @\defnlibxname{cpp_lib_atomic_ref}@ 201806L // also in \libheader{atomic}
#define @\defnlibxname{cpp_lib_atomic_shared_ptr}@ 201711L // also in \libheader{memory}
#define @\defnlibxname{cpp_lib_atomic_value_initialization}@ 201911L // also in \libheader{atomic}, \libheader{memory}
#define @\defnlibxname{cpp_lib_atomic_wait}@ 201907L // also in \libheader{atomic}
#define @\defnlibxname{cpp_lib_barrier}@ 201907L // also in \libheader{barrier}
#define @\defnlibxname{cpp_lib_bit_cast}@ 201806L // also in \libheader{bit}
Expand Down

0 comments on commit bbb4626

Please sign in to comment.