ISO/IEC JTC1 SC22 WG21 N3278 = 11-0048 - 2011-03-25
Submitted to a Candid World by the Concurrency Subgroup in Committee Assembled as edited by Lawrence Crowl.
Introduction
CWG 1176 editorial C1X
1.10 Multi-threaded executions and data races [intro.multithread]
CWG 1177 editorial C1X
1.10 Multi-threaded executions and data races [intro.multithread]
LWG 964 technical CH 1, US 2
30.5.2 Class condition_variable_any [thread.condition.condvarany]
LWG 1364 technical CH 19
18.8.5 Exception propagation [propagation]
LWG 1457 editorial GB 130; LWG 1460 technical US 154
29.2 Header <atomic>
synopsis [atomics.syn]
29.4 Lock-free property [atomics.lockfree]
29.5 Atomic types [atomics.types.generic]
LWG 1502 technical US 195
30.6.4 Shared state [futures.state]
LWG 1507 technical US 196, US 197, US 199
30.4.1.2 Mutex types[thread.mutex.requirements.mutex]
30.5 Condition variables [thread.condition]
30.6.5 Class template promise
[futures.promise]
LWG 1515 technical US 208
30.6.4 Shared state [futures.state]
LWG 1526 technical GB 111
18.10 Other runtime support [support.runtime]
LWG 2023 editorial
30.4.2.1 Class template lock_guard [thread.lock.guard]
30.4.2.2 Class template unique_lock [thread.lock.unique]
30.4.2.2.1 unique_lock constructors, destructor, and assignment [thread.lock.unique.cons]
30.4.2.2.2 unique_lock locking [thread.lock.unique.locking]
LWG 2024 editorial
29.5 Atomic types [atomics.types.generic]
LWG 2025 editorial
30.6.9.1 packaged_task member functions [futures.task.members]
LWG 2034 technical
29.3 Order and consistency [atomics.order]
LWG 2037 technical
29.2 Header
29.6.1 General operations on atomic types [atomics.types.operations.general]
29.6.2 Templated operations on atomic types [atomics.types.operations.templ]
29.6.3 Arithmetic operations on atomic types [atomics.types.operations.arith]
The following issues have been resolved by the Concurrency Subgroup. They have changes that are either technical since the issues documents, N3236 C++ Standard Core Language Active Issues, Revision 75 and N3245 C++ Standard Library Active Issues List (Revision R74) or editorial since the issues documents. Editorial changes respond to changes in the working draft since the proposed resolution was written.
Change the wording from CWG 1176, which has been incorporated into the draft. This makes the definition consistent with its uses in both the C and C++ drafts.
Edit paragraph 7 as follows.
A release sequence
fromheaded by a release operation A on an atomic object M is a maximal contiguous sub-sequence of side effects in the modification order of M, where the first operation is A and every subsequent operation either is performed by the same thread that performed the release or is an atomic read-modify-write operation.
Change the wording from CWG, which has been incorporated into the draft, to reflect WG14s sense of grammar.
Edit the first first bullet of paragraph 10 as follows.
A performs a release operation on an atomic object M, and,
onin another thread, B performs a consume operation on M and reads a value written by any side effect in the release sequence headed by A, or
Add a new paragraph after paragraph 2 as follows.
Throws:
bad_alloc
orsystem_error
when an exception is required (30.2.2).
Add a new paragraph after paragraph above as follows.
Error conditions:
resource_unavailable_try_again
— if any native handle type manipulated is not available.operation_not_permitted
— if the thread does not have the privilege to perform the operation.
Add a new paragraph after paragraph 6 as follows.
For purposes of determining the presence of a data race, operations on
exception_ptr
shall access and modify only theexception_ptr
objects themselves and not the exceptions they refer to. Use ofrethrow_exception
onexception_ptr
objects that refer to the same exception object shall not introduce a data race. [Note: ifrethrow_exception
rethrows the same exception (rather than a copy) then concurrent access to that rethrown exception object may introduce a data race. Changes in the number ofexception_ptr
objects that refer to a particular exception do not introduce a data race. —end note]
<atomic>
synopsis [atomics.syn]Edit the synopsis as follows.
namespace std { // 29.3, order and consistency enum memory_order; template <class T> T kill_dependency(T y); // 29.4, lock-free property #define ATOMIC_BOOL_LOCK_FREE unspecified #define ATOMIC_CHAR_LOCK_FREE unspecified #define ATOMIC_CHAR16_T_LOCK_FREE unspecified #define ATOMIC_CHAR32_T_LOCK_FREE unspecified #define ATOMIC_WCHAR_T_LOCK_FREE unspecified #define ATOMIC_SHORT_LOCK_FREE unspecified #define ATOMIC_INT_LOCK_FREE unspecified #define ATOMIC_LONG_LOCK_FREE unspecified #define ATOMIC_LLONG_LOCK_FREE unspecified #define ATOMIC_POINTER_LOCK_FREE unspecified // 29.5, generic types template<class T> struct atomic; template<> struct atomic<integral>; template<class T> struct atomic<T*>; // 29.6.1, general operations on atomic types // In the following declarations, atomic_type is either // atomic<T> or a named base class for T from // Table 145 or inferred from // Table 146 or from bool. … }
Edit the synopsis as follows.
#define ATOMIC_BOOL_LOCK_FREE unspecified #define ATOMIC_CHAR_LOCK_FREE
implementation-definedunspecified #define ATOMIC_CHAR16_T_LOCK_FREEimplementation-definedunspecified #define ATOMIC_CHAR32_T_LOCK_FREEimplementation-definedunspecified #define ATOMIC_WCHAR_T_LOCK_FREEimplementation-definedunspecified #define ATOMIC_SHORT_LOCK_FREEimplementation-definedunspecified #define ATOMIC_INT_LOCK_FREEimplementation-definedunspecified #define ATOMIC_LONG_LOCK_FREEimplementation-definedunspecified #define ATOMIC_LLONG_LOCK_FREEimplementation-definedunspecified #define ATOMIC_POINTER_LOCK_FREE unspecified
Edit the paragraph 1 as follows.
The
ATOMIC_…_LOCK_FREE
macros indicate the lock-free property of the corresponding atomic types, with the signed and unsigned variants grouped together. The properties also apply to the corresponding (partial) specializations of theatomic
template. A value of 0 indicates that the types are never lock-free. A value of 1 indicates that the types are sometimes lock-free. A value of 2 indicates that the types are always lock-free.
Edit paragraph 2 as follows.
The semantics of the operations on specializations of
atomic
are defined in 29.6 [atomics.types.operations].
Edit paragraph 3 as follows.
Specializations and instantiations of the
atomic
template shall have a deleted copy constructor, a deleted copy assignment operator, and aconstexpr
value constructor.
Edit paragraph 3 as follows.
There
areshall be full specializationsoverfor the integral types(char
,signed char
,unsigned char
,short
,unsigned short
,int
,unsigned int
,long
,unsigned long
,long long
,unsigned long long
,char16_t
,char32_t
, andwchar_t
, and any other types needed by the typedefs in the header<cstdint>
)on theatomic
class template. For each integral type integral, the specializationatomic<integral>
provides additional atomic operations appropriate to integral types.[Editor's note: I'm guessing that this is the correct rendering of the text in the paper; if this sentence was intended to impose a requirement, rather than a description, it will have to be changed.]There shall be a specializationatomic<bool>
which provides the general atomic operations as specified in 29.6.1 [atomics.types.operations.general].
Edit paragraph 5 as follows.
The atomic integral specializations and the specialization
atomic<bool>
shall have standard layout. They shall each have a trivial default constructor and a trivial destructor. They shall each support aggregate initialization syntax.
Edit paragraph 6 as follows.
There
areshall be pointer partial specializationsonof theatomic
class template. These specializations shall have trivial default constructors and trivial destructors.
Edit paragraph 7 as follows.
There
areshall be named types corresponding to the integral specializations ofatomic
, as specified in Table 145. In addition, there shall be named typeatomic_bool
corresponding to the specializationatomic<bool>
. Each named type is either a typedef to the corresponding specialization or a base class of the corresponding specialization. If it is a base class, it shall support the same member functions as the corresponding specialization.
Edit paragraph 8 as follows.
There
areshall be atomic typedefs corresponding to the typedefs in the header<inttypes.h>
as specified in Table 146.
Edit paragraph 10 as follows.
Accesses to the same shared state conflict (1.10).Accesses to the result of the same shared state may conflict (1.10). [Note: This explicitly specifies that the result of the shared state is visible in the objects that reference this state in the sense of data race avoidance ([res.on.data.races]). For example, concurrent accesses through references returned byshared_future::get()
[futures.shared_future]) must either use read-only operations or provide additional synchronization. —end note]
Edit paragraph 5 as follows.
The implementation shall provide lock and unlock operations, as described below.
The implementation shall serialize those operations.For purposes of determining the existence of a data race, these behave as atomic operations (1.10 [intro.multithread]). The lock and unlock operations on a single mutex shall appear to occur in a single total order. [Note: this can be viewed as the modification order (1.10 [intro.multithread]) of the mutex. —end note] [Note: Construction and destruction of an object of a mutex type need not be thread-safe; other synchronization should be used to ensure that mutex objects are initialized and visible to other threads. —end note]
After the Effects paragraph 7, add a new paragraph as follows.
Synchronization: The call to
notify_all_at_thread_exit
and the completion of the destructors for all the current thread's variables of thread storage duration synchronize with (1.10 [intro.multithread]) calls to functions waiting oncond
.
promise
[futures.promise]After paragraph 1, insert new paragraph as follows.
The
set_value
,set_exception
,set_value_at_thread_exit
, andset_exception_at_thread_exit
member functions behave as though they acquire a single mutex associated with the promise while updating the promise.
Delete synchronization clauses of paragraph 17.
Synchronization: calls toset_value
andset_exception
on a single promise object are serialized. [Note: And they synchronize and serialize with other functions through the referred shared state. —end note]
Delete synchronization clauses of paragraph 21.
Synchronization: calls toset_value
andset_exception
on a single promise object are serialized. [Note: And they synchronize and serialize with other functions through the referred shared state. —end note]
Add a new paragraph after paragraph 9 as follows.
Some functions, e.g.
promise::set_value_at_thread_exit()
, delay making the shared state ready until the calling thread exits. The destruction of each of that thread's thread storage duration [3.7.2, basic.stc.thread] objects is sequenced before making that shared state ready.
After paragraph 5 add a new paragraph as follows.
A call to thesetlocale
function may introduce a data race with other calls to thesetlocale
function or with calls to functions that are affected by the current C locale. The implementation shall behave as if no library function other thanlocale::global()
calls thesetlocale
function.
Remove paragraph 2.
The suppliedMutex
type shall meet theLockable
requirements (30.2.5.3).
The intent (in paragraphs 1-3) is to make BasicLockable
the fundamental requirement for unique_lock
.
We also update the note to reflect these changes
and synchronize one remaining reference of 'mutex'
by the proper term 'lockable object'
in sync to the wording changes of lock_guard
Edit paragraph 1 as follows.
... The behavior of a program is undefined if the contained pointer
pm
is not null and themutexlockable object pointed to bypm
does not exist for the entire remaining lifetime (3.8) of theunique_lock
object. The suppliedMutex
type shall meet theBasicLockable
requirements (30.2.5.2).[Editor's note: BasicLockable is redundant, since the following additional paragraph requires Lockable.]
Remove paragraph 2 as follows.
The suppliedMutex
type shall meet theLockable
requirements (30.2.5.3).
Edit paragraph 3 as follows.
[Note:
unique_lock<Mutex>
meets theBasicLockable
requirements. IfMutex
meets theLockable
requirements ([thread.req.lockable.req]),unique_lock<Mutex>
also meets theLockable
requirements and ifMutex
meets theTimedLockable
requirements (30.2.5.4),unique_lock<Mutex>
also meets theTimedLockable
requirements. — end note ]
Add the now necessary
member-wise additional constraints for Lockable
.
Edit paragraph 8 regarding
unique_lock(mutex_type& m, try_to_lock_t)
as follows.
Requires: The supplied
Mutex
type shall meet theLockable
requirements ([thread.req.lockable.req]). Ifmutex_type
is not a recursive mutex the calling thread does not own the mutex.
Add the now necessary
member-wise additional constraints for Lockable
.
Add a new paragraph after the try_lock
declaration
and before paragraph 4 as follows.
Requires: The supplied
Mutex
type shall meet theLockable
requirements ([thread.req.lockable.req]).
Change 29.5 [atomics.types.generic] p. 6 as indicated:
Edit paragraph 6 as follows.
There are pointer partial specializations on the
atomic
class template. These specializations shall have standard layout, trivial default constructors, and trivial destructors. They shall each support aggregate initialization syntax.
Rename parameter other to rhs in the move constructor.
packaged_task(packaged_task&&
otherrhs) noexcept;
Rename parameter other to rhs in paragraph 5.
Effects: constructs a new
packaged_task
object and transfers ownership of's shared state to
otherrhs*this
, leavingwith no shared state.
otherrhs
Rename parameter other to rhs in paragraph 6.
Postcondition:
has no shared state.
otherrhs
Rename parameter other to rhs in the move assignment operator.
packaged_task& operator=(packaged_task&&
otherrhs);
Edit paragraph 7 as follows.
Effects:
releases any shared state (30.6.4)
packaged_task(std::move(
.otherrhs)).swap(*this)
Edit paragraph 3 as follows.
There shall be a single total order S on all
memory_order_seq_cst
operations, consistent with the "happens before" order and modification orders for all affected locations, such that eachmemory_order_seq_cst
operation B that loads a value from an atomic object M observeseitherone of the following values:
- the result of the last
precedingmodificationaccording to this orderA of M that precedes B in S, if it exists, or- if A exists, the result of
an operationsome modification of M in the visible sequence of side effects with respect to B that is notmemory_order_seq_cst
and that does not happen before A, or- if A does not exist, the result of some modification of M in the visible sequence of side effects with respect to B that is not
memory_order_seq_cst
.[Note: .... —end note]
Note that the bullet list is introduced by this change.
Explicitly permit free functions.
Edit within the header <atomic>
synopsis as follows.
// 29.6.1, general operations on atomic types // In the following declarations, atomic-type is either //atomic<T>
or a named base class forT
from // Table 145 or inferred from // Table 146. // If it isatomic<T>
, then the declaration is a template // declaration prefixed withtemplate <class T>
template <class T>bool atomic_is_lock_free(const volatileatomic_typeatomic-type*);template <class T>bool atomic_is_lock_free(constatomic_typeatomic-type*);template <class T>void atomic_init(volatileatomic_typeatomic-type*, T);template <class T>void atomic_init(atomic_typeatomic-type*, T);template <class T>void atomic_store(volatileatomic_typeatomic-type*, T);template <class T>void atomic_store(atomic_typeatomic-type*, T);template <class T>void atomic_store_explicit(volatileatomic_typeatomic-type*, T, memory_order);template <class T>void atomic_store_explicit(atomic_typeatomic-type*, T, memory_order);template <class T>T atomic_load(const volatileatomic_typeatomic-type*);template <class T>T atomic_load(constatomic_typeatomic-type*);template <class T>T atomic_load_explicit(const volatileatomic_typeatomic-type*, memory_order);template <class T>T atomic_load_explicit(constatomic_typeatomic-type*, memory_order);template <class T>T atomic_exchange(volatileatomic_typeatomic-type*, T);template <class T>T atomic_exchange(atomic_typeatomic-type*, T);template <class T>T atomic_exchange_explicit(volatileatomic_typeatomic-type*, T, memory_order);template <class T>T atomic_exchange_explicit(atomic_typeatomic-type*, T, memory_order);template <class T>bool atomic_compare_exchange_weak(volatileatomic_typeatomic-type*, T*, T);template <class T>bool atomic_compare_exchange_weak(atomic_typeatomic-type*, T*, T);template <class T>bool atomic_compare_exchange_strong(volatileatomic_typeatomic-type*, T*, T);template <class T>bool atomic_compare_exchange_strong(atomic_typeatomic-type*, T*, T);template <class T>bool atomic_compare_exchange_weak_explicit(volatileatomic_typeatomic-type*, T*, T, memory_order, memory_order);template <class T>bool atomic_compare_exchange_weak_explicit(atomic_typeatomic-type*, T*, T. memory_order, memory_order);template <class T>bool atomic_compare)exchange_strong_explicit(volatileatomic_typeatomic-type*, T*, T, memory_order, memory_order);template <class T>bool atomic_compare_exchange_strong_explicit(atomic_typeatomic-type*, T*, T, memory_order, memory_order); // 29.6.2, templated operations on atomic types// In the following declarations, atomic_type is either //template <class T> T atomic_fetch_add(volatileatomic<T>
or a named base class forT
from // Table 145 or inferred from // Table 146.atomic-typeatomic<T>*, T); template <class T> T atomic_fetch_add(atomic-typeatomic<T>*, T); template <class T> T atomic_fetch_add_explicit(volatileatomic-typeatomic<T>*, T, memory_order); template <class T> T atomic_fetch_add_explicit(atomic-typeatomic<T>*, T, memory_order); template <class T> T atomic_fetch_sub(volatileatomic-typeatomic<T>*, T); template <class T> T atomic_fetch_sub(atomic-typeatomic<T>*, T); template <class T> T atomic_fetch_sub_explicit(volatileatomic-typeatomic<T>*, T, memory_order); template <class T> T atomic_fetch_sub_explicit(atomic-typeatomic<T>*, T, memory_order); template <class T> T atomic_fetch_and(volatileatomic-typeatomic<T>*, T); template <class T> T atomic_fetch_and(atomic-typeatomic<T>*, T); template <class T> T atomic_fetch_and_explicit(volatileatomic-typeatomic<T>*, T, memory_order); template <class T> T atomic_fetch_and_explicit(atomic-typeatomic<T>*, T, memory_order); template <class T> T atomic_fetch_or(volatileatomic-typeatomic<T>*, T); template <class T> T atomic_fetch_or(atomic-typeatomic<T>*, T); template <class T> T atomic_fetch_or_explicit(volatileatomic-typeatomic<T>*, T, memory_order); template <class T> T atomic_fetch_or_explicit(atomic-typeatomic<T>*, T, memory_order); template <class T> T atomic_fetch_xor(volatileatomic-typeatomic<T>*, T); template <class T> T atomic_fetch_xor(atomic-typeatomic<T>*, T); template <class T> T atomic_fetch_xor_explicit(volatileatomic-typeatomic<T>*, T, memory_order); template <class T> T atomic_fetch_xor_explicit(atomic-typeatomic<T>*, T, memory_order); // 29.6.3, arithmetic operations on atomic types // In the following declarations, atomic-integral is either //atomic<T>
or a named base class forT
from // Table 145 or inferred from // Table 146. // If it isatomic<T>
, // then the declaration is a template specialization declaration prefixed with //template <>
template <>integral atomic_fetch_add(volatile atomic-integral*, integral);template <>integral atomic_fetch_add(atomic-integral*, integral);template <>integral atomic_fetch_add_explicit(volatile atomic-integral*, integral, memory_order);template <>integral atomic_fetch_add_explicit(atomic-integral*, integral, memory_order);template <>integral atomic_fetch_sub(volatile atomic-integral*, integral);template <>integral atomic_fetch_sub(atomic-integral*, integral);template <>integral atomic_fetch_sub_explicit(volatile atomic-integral*, integral, memory_order);template <>integral atomic_fetch_sub_explicit(atomic-integral*, integral, memory_order);template <>integral atomic_fetch_and(volatile atomic-integral*, integral);template <>integral atomic_fetch_and(atomic-integral*, integral);template <>integral atomic_fetch_and_explicit(volatile atomic-integral*, integral, memory_order);template <>integral atomic_fetch_and_explicit(atomic-integral*, integral, memory_order);template <>integral atomic_fetch_or(volatile atomic-integral*, integral);template <>integral atomic_fetch_or(atomic-integral*, integral);template <>integral atomic_fetch_or_explicit(atomic-integral*, integral, memory_order);template <>integral atomic_fetch_or_explicit(atomic-integral*, integral, memory_order);template <>integral atomic_fetch_xor(volatile atomic-integral*, integral);template <>integral atomic_fetch_xor(atomic-integral*, integral);template <>integral atomic_fetch_xor_explicit(volatile atomic-integral*, integral, memory_order);template <>integral atomic_fetch_xor_explicit(atomic-integral*, integral, memory_order);
Edit paragraph 1 as follows.
The implementation shall provide the functions and function templates identified as "general operations on atomic types" in 29.2 [atomics.syn].
Edit paragraph 2 as follows.
In the declarations of these functions and function templates, the name atomic-type refers to either
atomic<T>
or to a named base class forT
from Table 145 or inferred from Table 146.
Delete paragraph 2 as follows.
In the declarations of these templates,
the name atomic-type refers to
either
atomic<T>
or to a named base class for T
from Table 145 or inferred from Table 146.
Edit paragraph 1 as follows.
The implementation shall provide the functions and function template specializations identified as "arithmetic operations on atomic types" in 29.2 [atomics.syn].
Edit paragraph 2 as follows.
In the declarations of these functions and function template specializations, the name integral refers to an integral type and the name atomic-integral refers to either
atomic<
integral>
or to a named base class for integral from Table 145 or inferred from Table 146.