[cpp-threads] Asynchronous Function Proposal

Herb Sutter hsutter at microsoft.com
Fri Jun 5 09:53:58 BST 2009


Inline:

> -----Original Message-----
> From: cpp-threads-bounces at decadentplace.org.uk [mailto:cpp-threads-
> bounces at decadentplace.org.uk] On Behalf Of Lawrence Crowl
> Sent: Tuesday, June 02, 2009 5:36 PM
> To: C++ threads standardisation
> Subject: Re: [cpp-threads] Asynchronous Function Proposal
> 
> On 6/2/09, Herb Sutter <hsutter at microsoft.com> wrote:
> > Summary of my main suggested changes to the proposal:
> >
> >  - The async policy should be an enum (or similar), not a set of
> >    tag types.
> >
> >  - Remove variadic overloads, put async policy last with a
> >    default arg.  (Can't do this with tag types.)
> >
> >  - async() should return a unique_future, not a new kind of future
> >    (a new type is overkill and creates problems, e.g., that the
> >    current proposal doesn't allow getting a shared_future to an
> >    async() call; that problem was already solved by unique_future).
> >
> >  - The synchronous policy should semantically mean executing at
> >    the call point, not at get().
> >
> > Lawrence wrote:
> > > But those policies are what I proposed,
> >
> > Yes and no:
> >
> > Yes, you proposed those three and I agree those are the right
> > ones. I was responding to Peter's note about more kinds of policies
> > being 'core' (they aren't to me).
> >
> > But no, in the proposal they are not enumerators. Peter made a
> > good suggestion that these be enums or otherwise easy to specify at
> > run time, which also avoids proliferating overloads of tag types.
> 
> We have the same understanding.  I have no objection to making the
> policy a enum.
> 
> However, I did get a suggestion from Jeffrey Yasskin to make the
> policy object more visible.  Something like...
> 
> int parallel_sum(int* data, int size)
> {
>   int sum = 0;
>   if ( size < 1000 )
>     for ( int i = 0; i < size; ++i )
>       sum += data[i];
>   else {
>     std::async_policy_whatever policy_obj;
>     auto handle = std::async(policy_obj, parallel_sum,
>                              data+size/2, size-size/2);
>     sum += parallel_sum(data, size/2);
>     sum += handle.get();
>   }
>   return sum;
> }
> 
> Which would then permit associating the thread-local destruction
> with the policy object, if necessary.  Furthermore, one could
> pass the policy object in.
> 
> int parallel_sum(std::async_policy& policy_obj, int* data, int size)
> {
>   int sum = 0;
>   if ( size < 1000 )
>     for ( int i = 0; i < size; ++i )
>       sum += data[i];
>   else {
>     auto handle = std::async(policy_obj, parallel_sum,
>                              data+size/2, size-size/2);
>     sum += parallel_sum(data, size/2);
>     sum += handle.get();
>   }
>   return sum;
> }
> 
> { ...
>   std::async_policy_whatever policy_obj;
>   parallel_sum( policy_obj, gonzo_array, 1000000000 );
>   ...
> }
> 
> Comments?

Policy object vs. enum: Either works for me.

But syntax: I still dislike the policy object first, and the separate parameters. That is, why standardize 8 (or whatever) overloads and require this less-clear syntax:

  async(policy_obj, parallel_sum, data+size/2, size-size/2);

when we could provide a single overload and use normal function call syntax and default the policy object parameter:

  async( [=]{ parallel_sum( data+size/2, size-size/2) ); } /* , policy_obj */ );

?


> > > where "this thread" is defined as the thread that calls get().
> >
> > I didn't notice that -- I think that's wrong.  First, the
> > synchronous case should be the same as if the user hadn't written
> > async() around it.
> 
> First, the thread that calls get() will nearly always be the thread
> that calls async(), so I don't think it matters much in anything
> other than a standards sense.
> 
> Second, we cannot make async behave the same as not writing the
> async in the case where execution is not serial.  What we can do,
> and what I propose, is to make the async behave the same whether the
> policy is threaded, serial, or optional.  As I said in the paper,
> if we do as you suggest, the programmer must add more catch clauses
> to the code, and I don't think that is the right design.
> 
> > Second, there can be multiple gets due to shared_future (see
> > below).
> >
> > Also, what do you think of the other suggested changes:
> >
> >  - The policy parameter should go last and have a default argument,
> >    for symmetry with other stdlib practice (e.g., atomic<T>
> >    memory order policies).
> 
> That approach is fine with me if we can make async() work as does
> the std::thread constructor.
> 
> >  - Therefore, and for other reasons, we shouldn't provide
> >    the variadic form, and instead provide only the one form
> >    "future<...> async( F&&, AsyncPolicy = could_be_sync_or_async".
> 
> What will std::thread look like?  Who is writing the paper to
> modify it?
> 
> >  - We shouldn't propose a third future type. This one should
> >    return unique_future (and that and shared_future should be
> >    fixed if deemed necessary). Note that this fixes a usability
> >    issue with the current proposal, namely that the user can't
> >    put the result in a shared_future if copying is required.
> 
> Can you provide a use case for why this flexibility is helpful?
> After all, the original call was single-point as well.

I don't understand that last part. Of course there's a single call site; you always start a function (and now async task) in one place. But of course there can be multiple consumers of the result of the computation; you often use the result (and now future<result>) in multiple places.


> The choice here is whether we require an async that cannot be
> implemented in terms of the other existing interfaces.  I am
> not necessarily opposed to doing so, but it sure feels like we
> are shuffling issues under the carpet.  So, what I proposed can
> be implemented in terms of existing interfaces.  If we drop that
> requirement, we can avoid async_future.  But in doing so, I do not
> want the other issues lost.
> 
> --
> Lawrence Crowl
> 
> --
> cpp-threads mailing list
> cpp-threads at decadentplace.org.uk
> http://www.decadentplace.org.uk/cgi-bin/mailman/listinfo/cpp-threads




More information about the cpp-threads mailing list