[cpp-threads] Asynchronous Function Proposal

Lawrence Crowl Lawrence at Crowl.org
Fri Jun 19 21:27:22 BST 2009


On 6/19/09, Anthony Williams <anthony at justsoftwaresolutions.co.uk> wrote:
> Lawrence Crowl wrote:
>
> > Always invoke the function in a new thread.
> >    Note that we do not choose "another thread"
> >    because of the problems described in N2880
> >    <http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2880.html>.
> >    In particular, one cannot use thread pools without exposing
> >    them to the programmers. This pint has not reached consensus.
>
> s/pint/point/

Fixed.

> Note that choosing "a new thread" does not get round the issues
> from N2880, as the future may be discarded without waiting (as
> you highlight below), in which case you still essentially have
> a detached thread.

The destructor for the future joins with the thread (presuming
you have one), so the only way to get into trouble is to move
the future to the heap and abandon it there.  This risk is known,
and relatively unlikely compared to other risks.

> >    * Work launched asynchronously must necessarily transmit
> >      exceptions arising from the work to the point the value is
> >      requested. To avoid exception handling code in two places,
> >      we choose exclusively the one place we must have.
>
> I think that's a red herring. If the work is executed synchronously
> at the point of the async call, the return value or any exception
> thrown should be stored in the future as always.

Yes, it could, but the implementation would likely be slower.

Ignoring that, I like the fact that an exception can avoid executing
the async call.

> >    * Work stealing implementations will be ineffective if the
> >      async functions have already committed to an eager serial
> >      execution.
>
> If you've explicitly chosen serial execution this is another red
> herring --- it only matters in the case that the user selected the
> "implementation chooses" policy.

Agreed.  It was that policy that I was thinking of.

> > Eager semantics seem more natural when programmers think of
> > "waiting to use the return value".
>
> They also seem more natural when you select an "execute
> synchronously" policy. It seems surprising to me that explicitly
> specifying such a policy would NOT execute the work immediately.

I grant that.  I still think it was the right choice.

> Also, given a policy of "must_be_called", it would be surprising
> if the work did not actually get called (because the future was
> discarded without waiting)!

Good point.  This leads to the conclusion that Herb's names for
the policies are better in that respect.  The names are probably
affected by the new thread versus existing thread issue.

> >    * An implementation of |std::unique_future| that can track
> >      the task will necessarily impose an implementation burden
> >      on other uses of |std::unique_future|.
>
> The cost to other uses does not have to be high: a single flag
> check or virtual function call inside wait() and get() should
> suffice.

I guess that depends on what you consider high.  Conditions tend to
introduce pipeline bubbles and virtual calls tend to be barriers to
optimization.  I am not terribly concerned about this overhead in the
truly async case.  I am much more concerned about inducing overhead
in the other uses of existing futures and in the serial case.

Does anyone have working source for unique_future available for
experiments?  I'd rather not try to recreate it at the last minute
before the mailing.

> >    |~joining_future();|
> >
> >        /Effects:/ destroys |*this| and its associated state if
> >        no other object refers to that. If the invocation has
> >        been deferred, the invocation is not executed.
>
> What about if the invocation was deferred, but has already
> started/completed?

Bad language.  How about this:

|~joining_future();|
    /Effects:/ destroys <code>*this</code> and its associated state
    if no other object refers to that.  If the invocation has been
    deferred, but not yet executed via |get|, the invocation is
    not executed.


-- 
Lawrence Crowl



More information about the cpp-threads mailing list