On Wed, Jan 14, 2015 at 7:02 AM, Niall Douglas
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,
Yes, re-reading what I wrote, I think that was my point (whether planned or not) - we don't need to think about threads, but execution contexts.
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)
yep, that's the idea.
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
sure but how does it halt - via some kernel/system/library/... mechanism, or does it call ExecutionContext->WAIT()?
until the PROGRESS of some other EXECUTION CONTEXT calls promise.set_value() or set_exception().
until some other code does whatever it wants, setting whatever it wants, and calls ExecutionContext->RESUME() ie separate the setting the value from the resuming of the execution. (The tricky part: while still maintaining atomicity where necessary)
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/
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost