Boost logo

Boost :

Subject: Re: [boost] Futures
From: Niall Douglas (s_sourceforge_at_[hidden])
Date: 2015-01-14 07:02:29


On 13 Jan 2015 at 12:57, Gottlob Frege wrote:

> Let's see if I've captured everything:

Let me rewrite your rewrite ...

> - we want to get a value from (likely) another THREAD, and WAIT if it
> is not yet ready UNTIL it is ready, (whatever THREAD WAIT UNTIL mean)
> - a future (boost:: or std:: or hpx:: etc) is a (high-level!) wrapping
> of that concept
> - to be inter-operable we need the lower level concepts (in ALL-CAPS) exposed
>
> THREAD:
> we actually don't need to completely define what "another" THREAD is,
> we only need a partial definition of our OWN THREAD. ie the *thread of
> execution* of the current code,
> because any code (that we assume at some point runs) runs in some
> "thread of execution" - whether user mode thread, kernel thread, HPX,
> whatever...

If you replaced the word THREAD with EXECUTION CONTEXT, where that
means any of the following:

1. Kernel thread (stackful, 1:1 mapping, probably with some real
hardware concurrency, cooperative context switching preferred but if
too long elapses you get preempted by a timer)

2. Process thread (stackful, M:N mapping onto kernel threads,
cooperative context switching though the cooperative part may be done
for you by a local process runtime e.g. Fiber, ASIO, HPX, WinRT)

3. Functional/monadic call sequence (stateful though stackless,
because functional call sequence is always constexpr and must only
propagate state changes forwards, it can be safely suspended at any
time without issue e.g. Hana, Expected, future-promise incidentally)

4. Stackless coroutine (an elaboration of item 5, but you get to
write your code in a slightly less fragmented way which may aid
maintainability e.g. Coroutine, ASIO's duff device macros
implementing these)

5. Event callback handler (stackless, state is usually passed via a
single void * or equivalent (std::function), almost always a local
process runtime calls you when something happens e.g. NT Kernel APCs,
POSIX signals, POSIX AIO, ASIO)

This may explain why I am so keen that the compiler can optimise a
future-promise down to single digit opcodes. For EXECUTION CONTEXT 3
and 5 the compiler's optimiser is fully and partially available, and
can collapse whole sections of code.

> What we really need is access to the _controller_ of that thread of
> execution - ie typically the scheduler, but not a full scheduler
> interface. In recent C++ proposals this has been called the
> "execution agent", although I've been pushing for EXECUTION CONTEXT -
> the C++ object/interface that controls the context of the execution of
> the current set of instructions.

This is what the Executors concept was supposed to provide. I've
always felt that ASIO is THE standard C++ executor and indeed event
handling and dispatch framework, so go standardise on that instead of
reinventing wheels no one wants nor uses.

> WAIT:
> The running code needs to be able to get at its EXECUTION CONTEXT in
> order to be able to ask it WAIT.
> For a given EXECUTION CONTEXT, WAIT means stop "running" - stop using
> CPU, etc. No further PROGRESS (which turns out to be a hard term to
> define, but the committee is working on that)

The key really is PROGRESS rather than wait. A future wait() or get()
halts PROGRESS of the calling EXECUTION CONTEXT until the PROGRESS of
some other EXECUTION CONTEXT calls promise.set_value() or
set_exception().

PROGRESS applies equally to all five ways of doing tasklets above.

> UNTIL:
> Some *other* EXECUTION CONTEXT needs to be able to tell the
> aforementioned EXECUTION CONTEXT to RESUME.

Personally I'd add ABORT here too. Some ASIO operations which ought
to count as tasklets can be aborted, indeed so can kernel threads on
POSIX. I am unsure if i/o operations ought to be included in the five
types of EXECUTION CONTEXT above.

> The value is orthogonal - the value is just a memory location (unless
> we abstract that away!) and can be set via atomic operations or
> whatever. Once the value is set, you then call RESUME on the execution
> agent. From a value point-of-view, what you want is just an
> ObservableValue. ie when value is changed, call this callable
> (function, lambda, whatever). Given an ObservableValue, and an
> ExecutionAgent you can build a promise.

Sounds good.

Niall

-- 
ned Productions Limited Consulting
http://www.nedproductions.biz/ 
http://ie.linkedin.com/in/nialldouglas/



Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk