Recent Concurrency Issue Resolutions

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 synopsis [atomics.syn]
    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]

Introduction

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.

CWG 1176 editorial C1X

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.

1.10 Multi-threaded executions and data races [intro.multithread]

Edit paragraph 7 as follows.

A release sequence from headed 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.

CWG 1177 editorial C1X

Change the wording from CWG, which has been incorporated into the draft, to reflect WG14s sense of grammar.

1.10 Multi-threaded executions and data races [intro.multithread]

Edit the first first bullet of paragraph 10 as follows.

LWG 964 technical CH 1, US 2

30.5.2 Class condition_variable_any [thread.condition.condvarany]

Add a new paragraph after paragraph 2 as follows.

Throws: bad_alloc or system_error when an exception is required (30.2.2).

Add a new paragraph after paragraph above as follows.

Error conditions:

LWG 1364 technical CH 19

18.8.5 Exception propagation [propagation]

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 the exception_ptr objects themselves and not the exceptions they refer to. Use of rethrow_exception on exception_ptr objects that refer to the same exception object shall not introduce a data race. [Note: if rethrow_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 of exception_ptr objects that refer to a particular exception do not introduce a data race. —end note]

LWG 1457 editorial GB 130; LWG 1460 technical US 154

29.2 Header <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. 

  …
}

29.4 Lock-free property [atomics.lockfree]

Edit the synopsis as follows.


#define ATOMIC_BOOL_LOCK_FREE unspecified
#define ATOMIC_CHAR_LOCK_FREE implementation-definedunspecified
#define ATOMIC_CHAR16_T_LOCK_FREE implementation-definedunspecified
#define ATOMIC_CHAR32_T_LOCK_FREE implementation-definedunspecified
#define ATOMIC_WCHAR_T_LOCK_FREE implementation-definedunspecified
#define ATOMIC_SHORT_LOCK_FREE implementation-definedunspecified
#define ATOMIC_INT_LOCK_FREE implementation-definedunspecified
#define ATOMIC_LONG_LOCK_FREE implementation-definedunspecified
#define ATOMIC_LLONG_LOCK_FREE implementation-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 the atomic 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.

29.5 Atomic types [atomics.types.generic]

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 a constexpr value constructor.

Edit paragraph 3 as follows.

There are shall be full specializations over for 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, and wchar_t, and any other types needed by the typedefs in the header <cstdint>) on the atomic class template. For each integral type integral, the specialization atomic<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 specialization atomic<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 are shall be pointer partial specializations on of the atomic class template. These specializations shall have trivial default constructors and trivial destructors.

Edit paragraph 7 as follows.

There are shall be named types corresponding to the integral specializations of atomic, as specified in Table 145. In addition, there shall be named type atomic_bool corresponding to the specialization atomic<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.

LWG 1502 technical US 195

30.6.4 Shared state [futures.state]

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 by shared_future::get() [futures.shared_future]) must either use read-only operations or provide additional synchronization. —end note]

LWG 1507 technical US 196, US 197, US 199

30.4.1.2 Mutex types[thread.mutex.requirements.mutex]

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]

30.5 Condition variables [thread.condition]

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 on cond.

30.6.5 Class template promise[futures.promise]

After paragraph 1, insert new paragraph as follows.

The set_value, set_exception, set_value_at_thread_exit, and set_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 to set_value and set_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 to set_value and set_exception on a single promise object are serialized. [Note: And they synchronize and serialize with other functions through the referred shared state. —end note]

LWG 1515 technical US 208

30.6.4 Shared state [futures.state]

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.

LWG 1526 technical GB 111

18.10 Other runtime support [support.runtime]

After paragraph 5 add a new paragraph as follows.

A call to the setlocale function may introduce a data race with other calls to the setlocale function or with calls to functions that are affected by the current C locale. The implementation shall behave as if no library function other than locale::global() calls the setlocale function.

LWG 2023 editorial

30.4.2.1 Class template lock_guard [thread.lock.guard]

Remove paragraph 2.

The supplied Mutex type shall meet the Lockable requirements (30.2.5.3).

30.4.2.2 Class template unique_lock [thread.lock.unique]

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 the mutex lockable object pointed to by pm does not exist for the entire remaining lifetime (3.8) of the unique_lock object. The supplied Mutex type shall meet the BasicLockable requirements (30.2.5.2). [Editor's note: BasicLockable is redundant, since the following additional paragraph requires Lockable.]

Remove paragraph 2 as follows.

The supplied Mutex type shall meet the Lockable requirements (30.2.5.3).

Edit paragraph 3 as follows.

[Note: unique_lock<Mutex> meets the BasicLockable requirements. If Mutex meets the Lockable requirements ([thread.req.lockable.req]), unique_lock<Mutex> also meets the Lockable requirements and if Mutex meets the TimedLockable requirements (30.2.5.4), unique_lock<Mutex> also meets the TimedLockable requirements. — end note ]

30.4.2.2.1 unique_lock constructors, destructor, and assignment [thread.lock.unique.cons]

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 the Lockable requirements ([thread.req.lockable.req]). If mutex_type is not a recursive mutex the calling thread does not own the mutex.

30.4.2.2.2 unique_lock locking [thread.lock.unique.locking]

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 the Lockable requirements ([thread.req.lockable.req]).

LWG 2024 editorial

Change 29.5 [atomics.types.generic] p. 6 as indicated:

29.5 Atomic types [atomics.types.generic]

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.

LWG 2025 editorial

30.6.9.1 packaged_task member functions [futures.task.members]

Rename parameter other to rhs in the move constructor.

packaged_task(packaged_task&& other rhs) noexcept;

Rename parameter other to rhs in paragraph 5.

Effects: constructs a new packaged_task object and transfers ownership of other rhs's shared state to *this, leaving other rhs with no shared state.

Rename parameter other to rhs in paragraph 6.

Postcondition: other rhs has no shared state.

Rename parameter other to rhs in the move assignment operator.

packaged_task& operator=(packaged_task&& other rhs);

Edit paragraph 7 as follows.

Effects:

LWG 2034 technical

29.3 Order and consistency [atomics.order]

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 each memory_order_seq_cst operation B that loads a value from an atomic object M observes either one of the following values:

[Note: .... —end note]

Note that the bullet list is introduced by this change.

LWG 2037 technical

Explicitly permit free functions.

29.2 Header synopsis [atomics.syn]

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 for T from
// Table 145 or inferred from
// Table 146.
// If it is atomic<T>, then the declaration is a template
// declaration prefixed with template <class T>

template <class T>
bool atomic_is_lock_free(const volatile atomic_typeatomic-type*);
template <class T>
bool atomic_is_lock_free(const atomic_typeatomic-type*);
template <class T>
void atomic_init(volatile atomic_typeatomic-type*, T);
template <class T>
void atomic_init(atomic_typeatomic-type*, T);
template <class T>
void atomic_store(volatile atomic_typeatomic-type*, T);
template <class T>
void atomic_store(atomic_typeatomic-type*, T);
template <class T>
void atomic_store_explicit(volatile atomic_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 volatile atomic_typeatomic-type*);
template <class T>
T atomic_load(const atomic_typeatomic-type*);
template <class T>
T atomic_load_explicit(const volatile atomic_typeatomic-type*, memory_order);
template <class T>
T atomic_load_explicit(const atomic_typeatomic-type*, memory_order);
template <class T>
T atomic_exchange(volatile atomic_typeatomic-type*, T);
template <class T>
T atomic_exchange(atomic_typeatomic-type*, T);
template <class T>
T atomic_exchange_explicit(volatile atomic_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(volatile atomic_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(volatile atomic_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(volatile atomic_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(volatile atomic_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
// atomic<T> or a named base class for T from
// Table 145 or inferred from
// Table 146.

template <class T>
T atomic_fetch_add(volatile atomic-typeatomic<T>*, T);
template <class T>
T atomic_fetch_add(atomic-typeatomic<T>*, T);
template <class T>
T atomic_fetch_add_explicit(volatile atomic-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(volatile atomic-typeatomic<T>*, T);
template <class T>
T atomic_fetch_sub(atomic-typeatomic<T>*, T);
template <class T>
T atomic_fetch_sub_explicit(volatile atomic-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(volatile atomic-typeatomic<T>*, T);
template <class T>
T atomic_fetch_and(atomic-typeatomic<T>*, T);
template <class T>
T atomic_fetch_and_explicit(volatile atomic-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(volatile atomic-typeatomic<T>*, T);
template <class T>
T atomic_fetch_or(atomic-typeatomic<T>*, T);
template <class T>
T atomic_fetch_or_explicit(volatile atomic-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(volatile atomic-typeatomic<T>*, T);
template <class T>
T atomic_fetch_xor(atomic-typeatomic<T>*, T);
template <class T>
T atomic_fetch_xor_explicit(volatile atomic-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 for T from 
// Table 145 or inferred from 
// Table 146.
// If it is atomic<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);

29.6.1 General operations on atomic types [atomics.types.operations.general]

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 for T from Table 145 or inferred from Table 146.

29.6.2 Templated operations on atomic types [atomics.types.operations.templ]

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.

29.6.3 Arithmetic operations on atomic types [atomics.types.operations.arith]

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.