Document Number: N3041=10-0031
Date: 2010-02-15
Project: Programming Language C++

Detlef Vollmann <dv@vollmann.ch>

N3041: Futures and Async Cleanup

Introduction

The adoption of N2996 and N2997 at the same meeting caused some editorial trouble, as the papers both were based on the previous working paper and were not properly aligned. [Big apologies to the editor!]

This paper tries to clean up the whole [futures] sub-clause.

Acknowledgements

Thanks to Anthony Williams, Jonathan Wakely, Daniel Krügler, Alisdair Meredith and Alberto Ganesh Barbati for their comments and contributions to this paper.

Proposed Changes

LWG issue 1244 (New)

In 30.6.1 [futures.overview], header <future> synopsis:
Add to enum class future_errc:

result_not_asynchronous

LWG issue 1226 (Tentatively Ready)

In 30.6.1 [futures.overview], header <future> synopsis:
Change:

    constexpr error_code make_error_code(future_errc e);
    constexpr error_condition make_error_condition(future_errc e);

    extern const error_category* const future_category;

to

    error_code make_error_code(future_errc e);
    error_condition make_error_condition(future_errc e);

    const error_category& future_category();

LWG issue 1090 (Tentatively Ready)

In 30.6.1 [futures.overview], header <future> synopsis, after declaration of class template packaged_task:
Add:

    template <class R>
      void swap(packaged_task<R(ArgTypes...)>&, packaged_task<R(ArgTypes...)>&)

LWG issue 1315 (Tentatively Ready)

In 30.6.1 [futures.overview], header <future> synopsis:
Change:

    template <class F, class... Args>
      future<typename F::result_type>
      async(F&& f, Args&&... args);
    template <class F, class... Args>
      future<typename F::result_type>
      async(launch policy, F&& f, Args&&... args);

to

    template <class F, class... Args>
      future<typename result_of<F(Args...)>::type>
      async(F&& f, Args&&... args);
    template <class F, class... Args>
      future<typename result_of<F(Args...)>::type>
      async(launch policy, F&& f, Args&&... args);

LWG issue 1226 (Tentatively Ready)

In 30.6.2 [futures.errors] near paragraph 1:
Change:

extern const error_category* const future_category;
future_category shall point to a statically initialized object of a type derived from class error_category.
to
    const error_category& future_category();
Returns: A reference to an object derived from class error_category.
Near paragraph 3, change:
constexpr error_code make_error_code(future_errc e);
Returns: error_code(static_cast<int>(e), *future_category).

to

error_code make_error_code(future_errc e);
Returns: error_code(static_cast<int>(e), future_category()).
Near paragraph 4, change:
constexpr error_code make_error_condition(future_errc e);
Returns: error_condition(static_cast<int>(e), *future_category).

to

error_condition make_error_condition(future_errc e);
Returns: error_condition(static_cast<int>(e), future_category()).

LWG issue 1269 (New)

In 30.6.4 [futures.state], title:
Change:

Associated state

to

Associated asynchronous state

In 30.6.4 [futures.state], paragraph 1:
Change:

If fully initialized, objects of type future ([future.future]), shared_future ([future.shared_future]), atomic_future ([future.atomic_future]), promise ([future.promise) and packaged_task ([future.task]) reference some state that is potentially shared between several such objects.

to

If fully initialized, objects that synchronize results across threads can reference some state that is potentially shared between several such objects.

[Note: Futures, promises and tasks defined in this clause reference such associated asynchronous state. --end note]

In 30.6.4 [futures.state], paragraph 2:
Change:

This associated state consists of some state information and some (possibly not yet evaluated) result, which can be a (possibly void) value or an exception.

to

This associated asynchronous state consists of some state information and some (possibly not yet evaluated) result, which can be a (possibly void) value or an exception.

[Note: The result can be any kind of object including a function to compute that result, as used by async for policy=sync. --end note]

Before 20.6.4 [futures.state], paragraph 3:
Add:

Objects that read results from associated asynchronous state are called asynchronous return object.

In 30.6.4 [futures.state], paragraph 3:
Change:

The result of such an associated state can be set by

to

Objects that provide such a result, are called asynchronous providers. The result of such an associated asynchronous state is set by respective functions on the asynchronous provider.

[Note: Such as promises or tasks. --end note]

LWG issue 1272 (New)

In 30.6.5 [futures.promise], synopsis:
Remove:

      void set_value(const R& r);

LWG issue 1300 (Tentatively Ready)

In 30.6.5 [futures.promise], paragraph 12:
Change:

Effects: swap(*this, other)

to

Effects: Exchanges the associated states of *this and other.

In 30.6.5 [futures.promise], after paragraph 13:
Add:

Throws: Nothing.

LWG issue 1272 (New)

In 30.6.5 [futures.promise], before paragraph 17:
Change:

void set_value(const R& r);

to

void promise::set_value(const R& r);

LWG issue 1291 (New)

In 30.6.5 [futures.promise], paragraph 18:
Change:

Throws: future_error if its associated state is already ready.

to

Throws: future_error if its associated state is already ready or, for the first version an exception thrown by the copy constructor of R, or for the second version an exception thrown by the move constructor of R.

LWG issue 1275 (New)

In 30.6.6 [futures.unique_future], paragraph 1:
Change:

The class template future defines a type for asynchronous return objects which do not share their associated state. A default-constructed future has no associated state. future objects with associated state can only be created by use of promise ([future.promise]) or packaged_task ([future.task]) objects, and share their associated state with that promise or packaged_task. Their values or exceptions can be set by use of the promise ([future.promise]) or packaged_task ([future.task]) object that shares the same associated state.

to

The class template future defines a type for asynchronous return objects which do not share their associated asynchronous state with other asynchronous return objects. A default-constructed future has no associated asynchronous state. future objects with associated asynchronous state can be created by functions on asynchronous providers ([futures.state] or by the move constructor and share their associated asynchronous state with the original asynchronous provider. The result (values or exceptions) of future objects can be set by calling a respective function on an object that shares the same associated asynchronous state.

LWG issue 1273 (Tentatively Ready)

In 30.6.6 [futures.unique_future], paragraph 3, introduction:
Change:

The effect of calling any member function other than the destructor or the move-assignment operator on a future for which valid() == false is undefined.

to

The effect of calling any member function other than the destructor or the move-assignment operator or valid() on a future for which valid() == false is undefined.

Clean-up

In 30.6.6 [futures.unique_future], paragraph 21, wait():
Change:

Precondition: valid() == true
Effects: if the associated state contains a deferred function, executes the deferred function. Otherwise, blocks until the associated state is ready.

to

Requires: valid() == true
Effects: blocks until the associated asynchronous state is ready.

LWG issue 1244 (New)

In 30.6.6 [futures.unique_future], paragraph 22ff, wait_for:
Change:

Precondition: valid() == true
Effects: if the associated state contains a deferred function, the behavior is unspecified. Otherwise, blocks until the associated state is ready or until rel_time has elapsed.
Returns: true only if the associated state is ready.

to

Requires: valid() == true
Effects: blocks until the associated asynchronous state is ready or until rel_time has elapsed.
Returns: true only if the associated asynchronous state is ready.
Throws: future_error if an error condition occurs.
Error conditions:

In 30.6.6 [futures.unique_future], paragraph 25ff, wait_until:
Change:

Precondition: valid() == true
Effects: blocks until the associated state is ready or until the current time exceeds abs_time.
Returns: true only if the associated state is ready.

to

Requires: valid() == true
Effects: blocks until the associated asynchronous state is ready or until the current time exceeds abs_time.
Returns: true only if the associated asynchronous state is ready.
Throws: future_error if an error condition occurs.
Error conditions:

LWG issue 1275 (New)

In 30.6.7 [future.shared_future], paragraph 1, introduction:
Change:

The class template shared_future defines a type for asynchronous return objects which may share their associated state. A default-constructed shared_future has no associated state. A shared_future object with associated state can only be created from another shared_future with associated state or a future object with associated state. Their values or exceptions can be set by use of a promise ([future.promise]) or packaged_task ([future.task]) object that shares the same associated state.

to

The class template shared_future defines a type for asynchronous return objects which may share their associated asynchronous state with other asynchronous return objects. A default-constructed shared_future has no associated asynchronous state. A shared_future object with associated asynchronous state state can be created by conversion from a future object and share their associated asynchronous state with the original asynchronous provider of the associated state. The result (values or exceptions) of shared_future objects can be set by calling a respective function on an object that shares the same associated asynchronous state.

Clean-up

In 30.6.7 [future.shared_future], after paragraph 2, introduction:
Add:

The effect of calling any member function other than the destructor or the move-assignment operator or valid() on a shared_future for which valid() == false is undefined.

LWG issue 1304 (Tentatively Ready)

In 30.6.7 [future.shared_future], paragraph 4, shared_future():
Change:

Effects: constructs an empty shared_future that doesn't refer to an associated asynchronous state.

to

Effects: constructs an empty shared_future that doesn't refer to an associated state.
Postcondition: valid() == false
Throws: nothing.

LWG issue 1304 (Tentatively Ready), clean-up

In 30.6.7 [future.shared_future], paragraph 22, wait():
Change:

Effects: if the associated state contains a deferred function, executes the deferred function. Otherwise, blocks until the associated state is ready.

to

Requires: valid() == true
Effects: blocks until the associated asynchronous state is ready.

LWG issue 1304 (Tentatively Ready), LWG issue 1244 (New)

In 30.6.7 [future.shared_future], paragraph 23ff, wait_for():
Change:

Effects: if the associated state contains a deferred function, the behavior is unspecified. Otherwise, blocks until the associated state is ready or until rel_time has elapsed.
Returns: true only if the associated state is ready.

to

Requires: valid() == true
Effects: blocks until the associated asynchronous state is ready or until rel_time has elapsed.
Returns: true only if the associated asynchronous state is ready.
Throws: future_error if an error condition occurs.
Error conditions:

In 30.6.7 [future.shared_future], paragraph 25ff, wait_until():
Change:

Effects: blocks until the associated state is ready or until the current time exceeds abs_time.
Returns: true only if the associated state is ready.

to

Requires: valid() == true
Effects: blocks until the associated asynchronous state is ready or until the current time exceeds abs_time.
Returns: true only if the associated asynchronous state is ready.
Throws: future_error if an error condition occurs.
Error conditions:

LWG issue 1275 (New)

In 30.6.8 [futures.atomic_future], paragraph 1:
Change:

The class template atomic_future defines a type for asynchronous return objects. These objects can only be created by use of promise ([future.promise]) or packaged_task ([future.task]) objects. Their values or exceptions can be set by use of promise ([future.promise]) objects.

to

The class template atomic_future defines a type for asynchronous return objects which may share their associated asynchronous state with other asynchronous return objects. A single atomic_future object may be shared between different threads. A default-constructed atomic_future has no associated asynchronous state. atomic_future objects with associated asynchronous state can be created by conversion from a future object and share their associated asynchronous state with the original asynchronous provider of the associated state. The result (values or exceptions) of atomic_future objects can be set by calling a respective function on an object that shares the same associated asynchronous state.

LWG issue 1274 (Tentatively Ready)

In 30.6.8 [futures.atomic_future], paragraph 6, atomic_future(atomic_future<R>&& rhs):
Change:

atomic_future(atomic_future&& rhs);

to

atomic_future(future<R>&& rhs);

Clean-up

In 30.6.8 [futures.atomic_future], paragraph 7ff, operator=():
Change:

Precondition: this->valid() == false
Effects: assigns the contents of rhs to *this. [Note: So *this refers to the same associated state as rhs (if any). --end note]
Synchronization: This assignment performs an acquire operation on rhs and a release operation on the left-hand side.

to

Requires: this->valid() == false
Effects: assigns the contents of rhs to *this. [Note: So *this refers to the same associated asynchronous state as rhs (if any). --end note]
Synchronization: This assignment performs an acquire operation on rhs and a release operation on *this.

Clean-up

In 30.6.8 [futures.atomic_future], paragraph 17, is_ready()ff:
Remove:

bool is_ready() const;
Precondition: valid() == true
Returns: true only if the associated state is ready.
bool has_exception() const;
Returns: true only if the associated state is ready and the associated state contains an exception.
bool has_value() const;
Returns: true only if the associated state is ready and the associated state contains a value.

LWG issue 1305 (New), clean-up

In 30.6.8 [futures.atomic_future], paragraph 22, wait():
Change:

Effects: blocks until the associated state is ready.

to

Effects: blocks until the associated asynchronous state is ready.
Throws: future_error if an error condition occurs.
Error conditions:

LWG issue 1244 (New) and 1305 (New), clean-up

In 30.6.8 [futures.atomic_future], paragraph 23ff, wait_for:
Change:

Effects: blocks until the associated state is ready or until rel_time has elapsed.
Returns: true only if the associated state is ready.

to

Effects: blocks until the associated asynchronous state is ready or until rel_time has elapsed.
Returns: true only if the associated asynchronous state is ready.
Throws: future_error if an error condition occurs.
Error conditions:

In 30.6.8 [futures.atomic_future], paragraph 25ff, wait_until():
Change:

Effects: blocks until the associated state is ready or until the current time exceeds abs_time.
Returns: true only if the associated state is ready.

to

Effects: blocks until the associated asynchronous state is ready or until the current time exceeds abs_time.
Returns: true only if the associated asynchronous state is ready.
Throws: future_error if an error condition occurs.
Error conditions:

Clean-up

In 30.6.9 [futures.async], just after the title:
Add:

async provides a mechanism to launch a function potentially in a new thread and provides the result of the function in a future object, with which it shares an associated asynchronous state.

LWG issue 1315 (Tentatively Ready)

In 30.6.9 [futures.async] synopsis:
Change:

    template <class F, class... Args>
      future<typename F::result_type>
      async(F&& f, Args&&... args);
    template <class F, class... Args>
      future<typename F::result_type>
      launch policy, async(F&& f, Args&&... args);

to

    template <class F, class... Args>
      future<typename result_of<F(Args...)>::type>
      async(F&& f, Args&&... args);
    template <class F, class... Args>
      future<typename result_of<F(Args...)>::type>
      async(launch policy, F&& f, Args&&... args);

In 30.6.9 [futures.async], paragraph 2, after the Returns: clause: Add:

Effects: If the invocation is deferred, the associated asynchronous state is not ready until the function has completed. Calls to waiting functions (wait() or other functions defined in terms of wait()) on asynchronous return objects that share the associated asynchronous state created by this async() call synchronize. The first of such calls shall invoke the deferred function in the thread that called the waiting function; all other calls waiting for the same result shall block until the deferred function has completed. The completion of the invocation of the deferred function happens-before the calls to the waiting functions return.

In 30.6.9 [futures.async], after paragraph 3 (Synchronization):
Add:

If the invocation is not deferred, a call to a waiting function on asynchronous return objects that share the associated asynchronous state created by this async() call shall block until the associated thread has completed.

LWG issue 1315 (Tentatively Ready)

In 30.6.9 [futures.async], after paragraph 5:
Add:

Remarks: The first signature shall not participate in overload resolution if decay<F>::type is std::launch.

LWG issue 1090 (Tentatively Ready)

In 30.6.10 [futures.futures_task], synopsis, after definition of class template packaged_task:
Add:

    template <class R, class... Argtypes>
      void swap(packaged_task<R(ArgTypes...)>&, packaged_task<R(ArgTypes...)>&)

In 30.6.10 [futures.futures_task], after paragraph 20:
Add:

    template <class R, class... Argtypes>
      void swap(packaged_task<R(ArgTypes...)>& x, packaged_task<R(ArgTypes...)>& y)
Effects: x.swap(y)
Throws: nothing.