On 29/10/2007, Andreas Raab andreas.raab@gmx.de wrote:
Igor Stasenko wrote:
but it is still deadlock-free since there is no wait involved (neither "classic" nor "busy-wait). In fact, we use recursions like the above in various places in Croquet.
See, unless you make all message sends in language as futures, you can't guarantee that some code will not end up with locking semantics.
Not "all messages sends". Only messages between concurrent entities (islands). This is the main difference to the all-out actors model (where each object is its own unit of concurrency) and has the advantage that you can reuse all of todays single-threaded code.
How would you define a boundaries of these entities in same image? Could you illustrate by some simple examples, or strategy which can be used for using them for concurrent execution within single VM? I'm very interested in practical usage of futures myself. What will you do, or how you would avoid the situation , when sometimes a two different islands containing a reference to the same object in VM will send direct messages to it, causing racing condition?
The difference between distributed computing and parallel (or concurrent) computing with shared memory is, that with shared memory, any change of state of any object are automatically propagated on entire image, while in distributed - not.
Lets see , what is happen if we have only a future sends. Then, given code: a print. b print.
will not guarantee that a will be printed before b.
Actually it will, if and only if a and b are in the same unit of concurrency (island). Your example is a bit misleading because of having different receivers - if those were in different islands then indeed there will be no guarantee that a prints before b. So for simplicity let's change this to:
Transcript future print: a. Transcript future print: b.
Do we need a whenResolved: block to serialize execution? No we don't because messages between two islands are executed in the order in which they were scheduled. Everything else would be a straight ticket to insanity ;-)
Yes. But this example is significant one. Sometimes i want these messages run in parallel, sometimes i don't. Even for single 'island'. Then, for general solution we need these islands be a very small (a smaller one is a single object) or contain big number of objects. The question is, how to give control of their sizes to developer. How developer can define a boundaries of island within single image? I will not accept any solutions like 'multiple images' because this drives us into distributed computing domain, which is _NOT_ concurrent computing anymore, simple because its not using shared memory, and in fact there is no sharing at all, only a glimpse of it.
Yes, we can make 'futureA whenComplete:' check implicitly (by modifying VM), then we can preserve old code. But do we really need a futures everywhere?
No, we don't. See above.
Or we give up with an imperative style and use something different which fits better with futures, or we give up with futures.
The nice thing about futures is that they can be put on top of everything else. We use them in Croquet today.
Or, we using both of them by mixing.. (which i think is most appropriate).. But then, stating that such system can be really lock-free, is wrong, because it depends on decision of concrete developer and his code.
This may be the outcome for an interim period. The good thing here is that you can *prove* that your program is deadlock-free simply by not using waits. And ain't that a nice property to have.
you mean waits like this (consider following two lines of code run in parallel):
[ a isUnlocked ] whileFalse: [ ]. b unlock.
and
[ b isUnlocked] whileFalse: []. a unlock.
You can remove waits, but can't remove a bad usage patterns from the brain of developer :) And how could you guarantee, that any bit of code in current ST image does not contain such hidden locks - like a loops or recursive loops which will never return until some external entity will change the state of some object(s)?
As for GC - you have automatic memory management instead of manual. But there's no automatic algorithm management and never will be , given any language :)
And what's that supposed to mean?
I pointed that futures as an 'automatic lock-free' approach is not quite parallel to 'automatic memory management by GC'.
The similarity is striking. Both in terms of tradeoffs (trade low-level control for better productivity) as well as the style of arguments made against it ;-) Not that I mind by the way, I find these discussions necessary.
The striking is, that introducing GC does good things - removing a necessity to care about memory, which helps a lot in developing and makes code more clear and smaller. But i can't see how futures does same. There are still lot things to consider for developer even by using futures. Of course, i dont have practice in using futures, and can't tell the difference, but to what i see, it's not that easy to use comparing to automatic memory management. Yes, its easy to pick a random piece of code and blindly type a word 'future'. But i don't think that every such piece will work as before ;)
Cheers,
- Andreas