This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of Resolved status.
promise::XXX_at_thread_exit
functions have no
synchronization requirementsSection: 32.10.6 [futures.promise] Status: Resolved Submitter: INCITS Opened: 2010-08-25 Last modified: 2016-01-28
Priority: Not Prioritized
View other active issues in [futures.promise].
View all other issues in [futures.promise].
View all issues with Resolved status.
Discussion:
Addresses US-199
promise::XXX_at_thread_exit
functions have no
synchronization requirements. Specifying synchronization
for these member functions requires coordinating with the
words in 32.10.6 [futures.promise]/21 and 25, which give synchronization
requirements for promise::set_value
and
promise::set_exception
(32.10.6 [futures.promise] p. 26 ff., p. 29 ff.).
[ Resolution proposed by ballot comment: ]
Change 32.10.6 [futures.promise]/21 to mention
set_value_at_thread_exit
andset_exception_at_thread_exit;
with this text, replace 32.10.6 [futures.promise]/25 and add two new paragraphs, after 32.10.6 [futures.promise]/28 and 32.10.6 [futures.promise]/31.
[2011-03-8: Lawrence comments and drafts wording]
This comment applies as well to other *_at_thread_exit
functions. The following resolution adds synchronization paragraphs
to all of them and edits a couple of related synchronization
paragraphs.
[2011-03-09: Hans and Anthony add some improvements]
[2011-03-19: Detlef comments]
In regard to the suggested part:
These operations do not provide any ordering guarantees with respect to other operations, except through operations on futures that reference the same shared state.
I would like this to change to:
These operations do not provide any ordering guarantees with respect to other operations on the same promise object. [Note: They synchronize with calls to operations on objects that refer to the same shared state according to 32.10.5 [futures.state]. — end note]
The current proposed resolution has exactly the same paragraph at for places. I propose to have it only once as new paragraph 2.
This also covers 1504(i) (US-196) and 1505(i) (US-197). US-197 is essentially rejected with this resolution, but a clarification is added that the normative wording is already in 32.10.5 [futures.state].
Proposed Resolution
Edit 32.6.4.2 [thread.mutex.requirements.mutex] paragraph 5 as follows:
5 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 (6.9.2 [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 (6.9.2 [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 ]Edit 32.7 [thread.condition] paragraphs 6-9 as follows:
void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk);-6- Requires:
lk
is locked by the calling thread and either
- no other thread is waiting on
cond
, orlk.mutex()
returns the same value for each of the lock arguments supplied by all concurrently waiting (viawait
,wait_for
, orwait_until
) threads.-7- Effects: transfers ownership of the lock associated with
lk
into internal storage and schedulescond
to be notified when the current thread exits, after all objects of thread storage duration associated with the current thread have been destroyed. This notification shall be as iflk.unlock(); cond.notify_all();-?- Synchronization: The call to
-8- Note: The supplied lock will be held until the thread exits, and care must be taken to ensure that this does not cause deadlock due to lock ordering issues. After callingnotify_all_at_thread_exit
and the completion of the destructors for all the current thread's variables of thread storage duration synchronize with (6.9.2 [intro.multithread]) calls to functions waiting oncond
.notify_all_at_thread_exit
it is recommended that the thread should be exited as soon as possible, and that no blocking or time-consuming tasks are run on that thread. -9- Note: It is the user's responsibility to ensure that waiting threads do not erroneously assume that the thread has finished if they experience spurious wakeups. This typically requires that the condition being waited for is satisfied while holding the lock onlk
, and that this lock is not released and reacquired prior to callingnotify_all_at_thread_exit
.Edit 32.10.6 [futures.promise], paragraphs 14-27 as follows:
void promise::set_value(const R& r); void promise::set_value(R&& r); void promise<R&>::set_value(R& r); void promise<void>::set_value();-14- Effects: atomically stores the value
-15- Throws:r
in the shared state and makes that state ready (32.10.5 [futures.state]).
future_error
if its shared state already has a stored value or exception, or- for the first version, any exception thrown by the copy constructor of
R
, or- for the second version, any exception thrown by the move constructor of
R
.-16- Error conditions:
promise_already_satisfied
if its shared state already has a stored value or exception.no_state
if*this
has no shared state.-17- Synchronization:
calls toFor purposes of determining the existence of a data race,set_value
andset_exception
on a singlepromise
object are serialized. [ Note: And they synchronize and serialize with other functions through the referred shared state. — end note ]set_value
,set_exception
,set_value_at_thread_exit
, andset_exception_at_thread_exit
behave as atomic operations (6.9.2 [intro.multithread]) on the memory location associated with thepromise
. Calls to these operations on a single promise shall appear to occur in a single total order. [Note: this can be viewed as the modification order (6.9.2 [intro.multithread]) of the promise. — end note] These operations do not provide any ordering guarantees with respect to other operations, except through operations on futures that reference the same shared state.void set_exception(exception_ptr p);-18- Effects: atomically stores the exception pointer
p
in the shared state and makes that state ready (32.10.5 [futures.state]).-19- Throws:
future_error
if its shared state already has a stored value or exception.-20- Error conditions:
promise_already_satisfied
if its shared state already has a stored value or exception.no_state
if*this
has no shared state.-21- Synchronization:
calls toFor purposes of determining the existence of a data race,set_value
andset_exception
on a singlepromise
object are serialized. [ Note: And they synchronize and serialize with other functions through the referred shared state. — end note ]set_value
,set_exception
,set_value_at_thread_exit
, andset_exception_at_thread_exit
behave as atomic operations (6.9.2 [intro.multithread]) on the memory location associated with thepromise
. Calls to these operations on a single promise shall appear to occur in a single total order. [Note: this can be viewed as the modification order (6.9.2 [intro.multithread]) of the promise. — end note] These operations do not provide any ordering guarantees with respect to other operations, except through operations on futures that reference the same shared state.void promise::set_value_at_thread_exit(const R& r); void promise::set_value_at_thread_exit(R&& r); void promise<R&>::set_value_at_thread_exit(R& r); void promise<void>::set_value_at_thread_exit();-22- Effects: Stores the value
-23- Throws:r
in the shared state without making that state ready immediately. Schedules that state to be made ready when the current thread exits, after all objects of thread storage duration associated with the current thread have been destroyed.future_error
if an error condition occurs. -24- Error conditions:
promise_already_satisfied
if its shared state already has a stored value or exception.no_state
if*this
has no shared state.-??- Synchronization: For purposes of determining the existence of a data race,
set_value
,set_exception
,set_value_at_thread_exit
, andset_exception_at_thread_exit
behave as atomic operations (6.9.2 [intro.multithread]) on the memory location associated with thepromise
. Calls to these operations on a single promise shall appear to occur in a single total order. [Note: this can be viewed as the modification order (6.9.2 [intro.multithread]) of the promise. — end note] These operations do not provide any ordering guarantees with respect to other operations, except through operations on futures that reference the same shared state.void promise::set_exception_at_thread_exit(exception_ptr p);-25- Effects: Stores the exception pointer
-26- Throws:p
in the shared state without making that state ready immediately. Schedules that state to be made ready when the current thread exits, after all objects of thread storage duration associated with the current thread have been destroyed.future_error
if an error condition occurs. -27- Error conditions:
promise_already_satisfied
if its shared state already has a stored value or exception.no_state
if*this
has no shared state.-??- Synchronization: For purposes of determining the existence of a data race,
set_value
,set_exception
,set_value_at_thread_exit
, andset_exception_at_thread_exit
behave as atomic operations (6.9.2 [intro.multithread]) on the memory location associated with thepromise
. Calls to these operations on a single promise shall appear to occur in a single total order. [Note: this can be viewed as the modification order (6.9.2 [intro.multithread]) of the promise. — end note] These operations do not provide any ordering guarantees with respect to other operations, except through operations on futures that reference the same shared state.Edit 32.10.10.2 [futures.task.members], paragraph 15-21 as follows:
void operator()(ArgTypes... args);-15- Effects:
-16- Throws: aINVOKE(f, t1, t2, ..., tN, R)
, wheref
is the stored task of*this
andt1
,t2
,...
,tN
are the values inargs...
. If the task returns normally, the return value is stored as the asynchronous result in the shared state of*this
, otherwise the exception thrown by the task is stored. The shared state of*this
is made ready, and any threads blocked in a function waiting for the shared state of*this
to become ready are unblocked.future_error
exception object if there is no shared state or the stored task has already been invoked. -17- Error conditions:
promise_already_satisfied
if the shared state is already ready.no_state
if*this
has no shared state.-18- Synchronization: a successful call to
operator()
synchronizes with (6.9.2 [intro.multithread]) a call to any member function of afuture
orshared_future
object that shares the shared state of*this
. The completion of the invocation of the stored task and the storage of the result (whether normal or exceptional) into the shared state synchronizes with (6.9.2 [intro.multithread]) the successful return from any member function that detects that the state is set to ready. [ Note:operator()
synchronizes and serializes with other functions through the shared state. — end note ]void make_ready_at_thread_exit(ArgTypes... args);-19- Effects:
-20- Throws:INVOKE(f, t1, t2, ..., tN, R)
, wheref
is the stored task andt1
,t2
,...
,tN
are the values inargs...
. If the task returns normally, the return value is stored as the asynchronous result in the shared state of*this
, otherwise the exception thrown by the task is stored. In either case, this shall be done without making that state ready (32.10.5 [futures.state]) immediately. Schedules the shared state to be made ready when the current thread exits, after all objects of thread storage duration associated with the current thread have been destroyed.future_error
if an error condition occurs. -21- Error conditions:
promise_already_satisfied
if the shared state already has a stored value or exception.no_state
if*this
has no shared state.-??- Synchronization: a successful call to
make_ready_at_thread_exit
synchronizes with (6.9.2 [intro.multithread]) a call to any member function of afuture
orshared_future
object that shares the shared state of*this
. The completion of
the invocation of the stored task and the storage of the result (whether normal or exceptional) into the shared state
the destructors for all the current thread's variables of thread storage duration
synchronize with (6.9.2 [intro.multithread]) the successful return from any member function that detects that the state is set to ready. [Note:
make_ready_at_thread_exit
synchronizes and serializes with other functions through the shared state. — end note]
Proposed resolution:
Resolved 2011-03 Madrid meeting by paper N3278