Concurrent Futures
Andreas Raab
andreas.raab at gmx.de
Sun Oct 28 06:38:15 UTC 2007
Ralph Johnson wrote:
> If E was automatically free from deadlock, why was this solution so complex?
Because it's trying to illustrate three three issues at once (security,
capabilities, concurrency) and consequently fails to illustrate either
one very well :-(
It is trivial to solve this problem via event-loop concurrency though.
Consider a class Table with operations "grabLeftFork:", "grabRightFork:"
(which take a seat index as argument and return the fork or nil). You
can now implement the dining philosophers "Croquet style" as follows:
Philosopher>>eat
"Start eating"
| leftForkPromise rightForkPromise |
"Try to aquire the left fork first"
leftForkPromise := table future grabLeftFork: seat.
leftForkPromise whenResolved:[:leftFork|
"If we couldn't get the left fork, we need to decide
what to do. Simply retry later but use a random amount
of time to avoid live-lock"
leftFork ifNil:[^(self future: self randomMSecs) eat].
rightForkPromise := table future grabRightFork: seat.
rightForkPromise whenResolved:[:rightFork|
rightFork ifNil:[
"Same as before, but return the fork first"
table future returnLeftFork: seat.
^(self future self randomMSecs) eat "still hungry"
] ifNotNil:[
"We got both forks, eat"
state := #eating.
"And return the forks when time is up"
^(self future: self timeToEat)
returnFork: leftFork and: rightFork
].
].
].
Note that there is no wait anywhere in the above - the only thing that
exists are #future sends that schedule messages to be executed at some
point later. Because of this, the philosopher never really "waits" for
anything; he will happily keep thinking (or grumbling ;-) until he
obtains the forks. Even *while* he is eating one could schedule an
emergency request to "drop those forks" if that were necessary.
Cheers,
- Andreas
More information about the Squeak-dev
mailing list
|