[cpp-threads] Asynchronous Function Proposal

Anthony Williams anthony at justsoftwaresolutions.co.uk
Mon Jun 8 22:53:29 BST 2009


Boehm, Hans wrote:
> And I don't currently see a reason exceptions shouldn't always be
> reported at the request point.
> 
> Thinking about this more, I'm not sure I fully understand the
> implications of allowing or disallowing execution at the call point.

If you allow exceptions from the *task* to be thrown at the point of the 
async() call then the user code has to be able to handle them being 
thrown there, as well as at the future.get() call site. If the async() 
call throws exceptions on its own (e.g. std::bad_alloc if not enough 
memory to allocate task) that is a different matter.

Disallowing exceptions from the task to be thrown at the async() call 
site doesn't mean the task can't be executed synchronously there --- it 
just means that the exception must be captured in the unique_future's 
associated state.

> It means the implementation has no way of throttling the number of
> pending tasks in various queues, where current implementations
> (notably TBB) apparently tend to do so.  Given the current API
> proposal, I guess we need space to store all the futures anyway, at
> least in the absence of nontrivial compiler optimizations.  Thus I'm
> not sure how major the impact would be.

A task could in theory carry a huge block of data with it, which it then 
reduced to a single int stored in the future (or even just the not 
ready/ready-with-value/ready-with-exception state of a 
std::unique_future<void>). Allowing a big queue of such objects would 
therefore require a lot of memory, which could be reduced to just the 
size of the state associated with the futures if the tasks were run 
synchronously when the queue was too large.

Any point that can run subtasks on the same thread as the caller needs 
to be flagged up, as it is important that the calling thread does not 
hold locks across such a call, or expect to be able to communicate with 
the subtask in other ways. If we are going to allow the async() call to 
run the task synchronously, then we need to clearly specify that fact. I 
think the this-thread/other-thread/any-thread policy choice suffices for 
this purpose, but I just wanted to emphasize that.

Also, at the risk of repeating myself, I do not think we can support 
running the subtask synchronously as part of a std::unique_future::get() 
call. Futures may be passed between threads, or may be converted into 
std::shared_future instances with multiple threads waiting, and you lose 
all information about the task associated with the future. Running tasks 
at the get() site is therefore extremely dangerous in general. My 
prototype task group for recursive parallel tasks therefore has a 
distinct handle type for subtasks, and the functions to wait for the 
task or retrieve the data are currently called execute_and_sync() and 
execute_and_get() to emphasize that they will execute the subtask if it 
hasn't already started on another thread.

Anthony
-- 
Author of C++ Concurrency in Action | http://www.manning.com/williams
just::thread C++0x thread library   | http://www.stdthread.co.uk
Just Software Solutions Ltd         | http://www.justsoftwaresolutions.co.uk
15 Carrallack Mews, St Just, Cornwall, TR19 7UL, UK. Company No. 5478976



More information about the cpp-threads mailing list