Future-based designs do not mix well with state machines' run-to- completion. <
Could you elaborate a little on that comment please? I have a had a couple of instances where I'm manipulating 'state' and transitioning from one to another - I would welcome some ideas on how to make this a bit cleaner.
A future.then() returns another future so isn't it just delaying the fact that I have to decide at some point what to do with the future object? Do I poll it, get() it or ignore it? Polling is tedious, ignore usually wrong, and get() means blocking. As a state machine run-to-completion is supposed to execute in no time, this is not a good option. Run-to-completion means: event is sent, transition is executed. Until it completes, the state machine is in an unstable state. This has to be kept as short as possible.
HPX uses futures as explicit means to express dependencies between tasks which allows for asynchronous execution without barriers. Surely, at some point you need to call get() on the top-most future representing the whole execution tree, but this is usually not an issue as most (if not all) applications have natural synchronization points imposed by their implemented logic. These future objects are a very useful construct allowing to express various kind of asynchrony in an application. But I'm sure you agree to that as more than half of the documentation of Boost.Asynchronous explains concepts based on using futures as a concept.
The reason for the non-blocking focus is that I'm using the library at work in an industrial 24/7 application. When working on the production line, blocking is a disaster. If an algorithm goes astray, or simply takes longer than usually, blocking the production line results in huge costs. Crashes due to races also. Asynchronous provides ways to avoid both.
Using futures, even if you have to call future::get() does not imply blocking. It implies possible suspension, which is a completely different beast. Calling future::get() on one task does not 'block' the kernel-thread running the task as it is now free to run other tasks.
I would say that non-blocking behaviour is one of the central goals of HPX. Continuations are only triggered when futures become ready and therefore blocking is avoided - so I don't think there's any disagreement there! Races are a problem, but a functional style of programming goes a long way to avoiding them.
I agree that HPX likely solves well the race problem, which is a great achievement. I feel both libraries solve quite different problems. Asynchronous is focusing on organizing objects into threads and building everything else on top of that. In that context, callbacks within these object's thread contexts make more sense than a fire-and-forget of a future.then();
Why do you think future::then() is fire& forget? Future::then is a means of turning a future into a callback, while the opposite can be achieved for instance by using a packaged task. So I'd say both concepts are equivalent in terms of provided functionality. The benefit of a future based approach (in my experience) is that it leads to a very functional style of programming, while encouraging value semantics. Both things naturally support race-free programming... The other benefit is that futures very much hide the notion of threads altogether, thus exposing higher level abstractions freeing the programmer's mind from tracking thousands (or more) execution states at the same time. Regards Hartmut --------------- http://boost-spirit.com http://stellar.cct.lsu.edu