[cpp-threads] Asynchronous Function Proposal

Herb Sutter hsutter at microsoft.com
Tue Jun 2 23:58:04 BST 2009


> I think this is getting a lot closer to something we might want.  And
> I'm increasingly convinced that we need to have this design somewhat
> nailed down before we finalize some features already in the draft.
> This discussion seems essential whether or not we decide to put this in
> C++0x.  I really don't think we want the current future in the standard
> if we can't use it here.

Agreed.

> But I'm still worried about whether we have enough of the details right
> here that this facility will actually be usable.  I don't have the
> necessary experience that I feel I can evaluate a design.  As far as I
> can tell:
> 
> - I believe this doesn't support a Cilk-like (or TBB-like?)
> implementation.  I believe Cilk effectively allows colder call frames
> to be stolen by another thread, for example.
[...]

A primary reason I've been advocating an "async()" facility, besides as a way to make async calls easy, was specifically to make sure that an async() with a default "could execute on this or another thread" policy could be implemented to run on a work stealing implementation, such as Cilk, TBB, or our own TPL/PPL/ConcRT. I haven't seen anything that would prevent that -- all you need to say is exactly "could execute on this or another thread" and IIUC that's all we need.


> - This is very different from Java thread pools, as it has to be, given
> the constraints.

Yes.


> - I don't have a clear intuition of how this could perform even with a
> simple tree-structured algorithm, like the ubiquitous fib example.
> Assuming an implementation that creates a thread 

Speaking to that assumption: I think that's one implementation, but it's not what my company would probably ship. We'd just have code like

  unique_future<T> result = async( [&]{ quicksort( /* left subrange */ ); } )
  ...
  result.get();

be basically the same as what in PPL (available in VS 2010 beta) we would write as

  task_group tg;
  tg.run( [&]{ quicksort( /* left subrange */ ); } );
  ...
  tg.wait();

(note that we still need to add futures to our system to make it more usable :-) ).


> when the number of
> threads is below a certain threshold, I would expect that depending on
> exact timing, we actually get a bunch of threads executing high-level
> tasks (if newly created threads start running quickly), or most of the
> available threads are initially assigned to small tasks low in the tree
> (if the initial task gets to spawn all the threads before anybody else
> gets a shot at it).  My intuition is that the former would result in
> acceptable performance, where the latter would be awful.  But the only
> way I seem to be able to control this is by avoiding the may_be_called
> policy.  Maybe this isn't as bad as I think it might be.  I just don't
> know.  Doug Lea or Arch Robison probably understands this better.  Is a
> better implementation possible?

Does the above help? Are there concerns that I'm missing?


> It seems to me that we're designing something here that's quite
> different from Cilk, TBB, or java.util.concurrent, which are perhaps
> the most established (?) systems in the area.

I don't think so, and I hope not. Put slightly differently: I think and hope we're designing something that could be trivially run on a work-stealing implementation if available, or on pooled or non-pooled threads otherwise.

Herb





More information about the cpp-threads mailing list