Managing C++ Associated Asynchronous State

ISO/IEC JTC1 SC22 WG21 N3129 = 10-0119 - 2010-08-20

Lawrence Crowl, crowl@google.com, Lawrence@Crowl.org

Problem
Solution
Wording
    30.6.4 Associated asynchronous state [futures.state]
    30.6.5 Class template promise [futures.promise]
    30.6.6 Class template future [futures.unique_future]
    30.6.7 Class template shared_future [futures.shared_future]
    30.6.8 Class template atomic_future [futures.atomic_future]
    30.6.10.1 packaged_task member functions [futures.task.members]

Problem

Within the Final Committee Draft, the specification for managing associated asynchronous state [futures.state] is confusing, sometimes omitted, and redundantly specified.

Solution

Define terms-of-art for releasing, making ready, and abandoning an associated asynchronous state. Define a term-of-art for waiting functions on an associated asynchronous state. Use those terms where appropriate.

This solution implements the intent of the existing wording. That is, there is no new functionality.

Wording

The wording is relative to the FCD.

30.6.4 Associated asynchronous state [futures.state]

Edit paragraph 3 as follows.

An asynchronous return object is an object that reads results from an associated asynchronous state. A waiting function of an asynchronous return object is one that potentially blocks to wait for the associated asynchronous state to be made ready.

Edit paragraph 5 as follows.

When the last reference to an associated asynchronous state is given up, any resources held by that associated asynchronous state are released. An asynchronous return object or an asynchronous provider release their associated asynchronous state as follows.

An asynchronous provider makes ready an associated asynchronous state as follows.

An asynchronous provider abandons an associated asynchronous state as follows.

30.6.5 Class template promise [futures.promise]

Edit paragraph 7, regarding the destructor, as follows.

Effects: if the associated asynchronous state of *this is not ready, stores an exception object of type future_error with an error condition of broken_promise Any threads blocked in a function waiting for the asynchronous state associated with *this to become ready are unblocked. Destroys *this and releases its reference to its associated asynchronous state if any. If this is the last reference to that associated asynchronous state, destroys that state. abandons any associated asynchronous state ([futures.state]).

Edit paragraph 8, regarding the move assignment operator, as follows.

Effects: abandons any associated asynchronous state ([futures.state]) and then as if promise<R>(std::move(rhs)).swap(*this).

Remove paragraph 9, as it is now redundant with the effects.

Postcondition: rhs has no associated asynchronous state. *this has the associated asynchronous state of rhs prior to the assignment.

Edit paragraph 18, regarding set_value, as follows.

Effects: atomically stores r in the associated asynchronous state and sets that state to ready. Any threads blocked in a call of a blocking function of any future that refers to the same associated asynchronous state as *this are unblocked. makes ready that state ([futures.state]).

Edit paragraph 22, regarding set_exception, as follows.

Effects: atomically stores p in the associated asynchronous state and sets that state to ready. Any threads blocked in a call of a blocking function of any future that refers to the same associated asynchronous state as *this are unblocked. makes ready that state ([futures.state]).

Edit paragraph 26, regarding set_value_at_thread_exit, as follows.

Effects: Stores r in the associated asynchronous state without making ready the associated asynchronous that state ready immediately. Schedules the associated asynchronous 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.

Edit paragraph 29, regarding set_exception_at_thread_exit, as follows.

Effects: Stores p in the associated asynchronous state without making ready the associated asynchronous that state ready immediately. Schedules the associated asynchronous 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.

30.6.6 Class template future [futures.unique_future]

Edit paragraph 10, regarding the destructor, as follows.

Effects:

Edit paragraph 11, regarding the move assignment operator, as follows.

Effects:

30.6.7 Class template shared_future [futures.shared_future]

Edit paragraph 13, regarding the destructor, as follows.

Effects:

Edit paragraph 14, regarding the move assignment operator, as follows.

Effects:

Edit paragraph 16, regarding the copy assignment operator, as follows.

Effects:

30.6.8 Class template atomic_future [futures.atomic_future]

Edit paragraph 9, regarding the destructor, as follows.

Effects:

Edit paragraph 10, regarding the copy assignment operator, as follows.

Effects:

30.6.10.1 packaged_task member functions [futures.task.members]

Edit paragraph 9, regarding the move assignment operator, as follows.

Effects:

Edit paragraph 10, regarding the destructor, as follows.

Effects: if the associated asynchronous state of *this is not ready, stores an exception object of type future_error with an error code of broken_promise. Any threads blocked in a function waiting for the associated asynchronous state of *this to become ready are unblocked. Destroys *this and releases its reference to its associated asynchronous state (if any). If this is the last reference to that associated asynchronous state, destroys that state. abandons any associated asynchronous state ([futures.state]).

Edit within paragraph 24, regarding make_ready_at_thread_exit, as follows.

.... this shall be done without making the state ready making ready that state ([futures.state]) immediately. ....

Edit paragraph 27, regarding reset, as follows.

Effects: returns the object to a state as if a newly-constructed instance had just been assigned to *this by *this = packaged_task(std::move(f)), where f is the task stored in *this. [Note: this constructs a new associated asynchronous state for *this. The old state is discarded, abandoned ([futures.state]). as described in the destructor for packaged_task. get_future may now be called again for *this.end note]