On 17 Oct 2014 at 19:42, Hartmut Kaiser wrote:
Yep. Using my new spinlock library, the one I built the safe erasing concurrent_unordered_map with.
What suspension mechanism does this rely on? Does it suspend the kernel thread?
Nothing currently, but it will use my failed proposed C11/pthreads permit object. Myself and Hans Boehm spent an awful lot of time back in the day getting that permit object to behave well under all sorts of weird load conditions. It's also portable, and is safe to destroy concurrent to signalling. It has a few other useful features too which makes it ideal as the standard kernel wait abstraction. I'll be keeping around a thread safe process wide cache of unused permit objects, so grabbing one lazily will usually be fast.
I can absolutely guarantee that this sequence always reduces to nothing: ...
While all of this demonstrates impressive optimization technologies, I don't think it's a relevant use case. In 99.9% of all use cases this is not applicable. So why worry?
This is a very valuable statement. It showed me that I was coming at non-allocating future promise all wrong design wise - I, like the present Concurrency TS, was thinking in terms of composing futures into continuations. It has suddenly dawned on me that this is all wrong - I should in fact be thinking in terms of *flow* of continuations, and that future-promise is simply where a river forks, or a vertex appears in a graph. That utterly changes the design. We still get non-allocating future-promise which template aliases a std::future compatible variant. But the design inverts inside out. We now hang future-promise onto thenables, not the other way round. I think I now understand where Louis Dionne was coming from in a private mail when he was trying to explain how Hana might do this stuff. I'm getting old and slow in the mind, but I ain't quite dead yet. I'll see if I can come up with a new prototype next week in time for the Urbana meeting.
FWIW, N4123 adds .then to the future<> type, not the promise<>.
Sure. That's because future.then() executes its continuations at the point of someone doing a future.get().
No, future.then() is called whenever somebody else sets the value (using promise.set_value()) - well except when using launch::deferred, but there all bets are off anyways.
Except launch::async | launch::deferred is the default launch policy for futures created from std::promise or a std::packaged_task, and so therefore it does indeed execute continuations at future.get(). See http://www.open-std.org/jtc1/sc22/WG21/docs/papers/2014/n4107.html, I see the pre-Urbana changes haven't changed this. There is value in both points of launch. I think personally it should be selectable. Anyway, the new design I have in mind makes .then() merely a backwards compatibility shim, the new design starts with everything being a continuation and promise-future is merely a potential transformation rather like a Haskell monadic bind. If you want a continuation to occur promise side and another future side, simply insert the promise-future construct in between the two in the overall sequence. Sorry, I'll hopefully show this in code later next week, I am probably being a bit excited and speaking nonsense.
As promise.then() attaches continuations to the promise instead, it would execute its continuations at the point of someone doing a promise.set_value() or promise.set_exception().
(Some might wonder why not subclass basic_promise<> and override the set_value()/set_exception() with custom behaviour? Unlike promise, basic_promise is designed to be customised and subclassed in a family of future-ish promise-ish types. It's a very valid point, but I worry about generic extension, see below).
I'd be absolutely against attaching continuations through the promise. It's conceptually wrong.
Agreed. Promise suspends a continuations sequence, Future resumes a sequence (optionally on another thread).
What do you mean by 'static continuation'? What's the difference to a continuation as defined in N4123?
Continuations in N4123 are big fat heavy things with an implied memory allocation and a probably std::function wrap. Continuations in N4213 let you do: future<int> &f; if(i_feel_like_it) f.then([]); Which is absolutely fine. However, sometimes you will always do: promise<int> &p; auto f=p.get_future().then([]); // always continue There a memory allocation and std::function wrap is totally unnecessary because the compiler has sufficient information to construct f statically, except that the present design in N4123 requires it. This is what I mean by static continuations - ones which always happen unconditionally. Niall -- ned Productions Limited Consulting http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/