Lots of concurrency

Andreas Raab Andreas.Raab at gmx.de
Fri Oct 19 20:49:04 UTC 2001


Lex,

[Let me point out here that I'm no expert in this area. Ken or any other
knowledgable person should chime in here]

> >
> > 	someAccount setAmount: someAmount getAmount + delta.
> >
> > (modifying the object from the outside) is doomed to fail.
> > You _must_ implement something like:
> >
> > Account>>addAmount: delta
> > 	amount := amount + delta.
>
>
> Why can't I?  Can't I write a #getAmount request?  Can't I write a
> #setAmount: request?  These are both useful in other contexts, after
> all.  So what's to stop me from combining them?

I think you can, but it's equivalent to assuming that after a sequence of
	tempColor := self color.
	self color: someOtherColor.
tempColor will still have the same value as self color. A lot of this (as
far as I understand) is "encoded" in the mind set of the programmer. You
wouldn't expect the above (e.g., "tempColor = self color" after these two
statements) and in a concurrent universe you wouldn't expect that the real
amount of your bank account is still the same after the query. It's kinda
like calling for the balance on your credit card - they always tell you
"this amount may have been reduced due to pending charges". Assuming that
the real value of your account is still the same after your query is nothing
but a guess. Sometimes it'll be true - and sometimes not.

It is perhaps important to note that concurrent programming does _not_
prevent you from making errors. The above would be considered an error in
Squeak and so would your #get and #set: example in a concurrent language.
Incidentally, that again leads to better OO design - I can't really see a
concurrent language that actually has explicit setters for crucial state
(which again leads to better service-oriented design). A bank account object
certainly would not and should not have a setter for the amount.

> A real example of this is in Scamper.  The sequence is (rephrased in
> terms of message-passing; it actually uses SharedQueue's):
>
> 	1. scamper says: "downloader startDownloading: url"
>
> 	2. " ... scamper displayes 'downloading' -- *assuming*
> the downloader is in a downloading state"
>
> 	3. downloader says:  "scamper documentArrived: doc"
>
> 	4. " ... scamper displays 'done' -- assuming the
> downloader is no longer downloading"
>
>
> The status line is only correct based on assumptions about what the
> downloader object is doing.  In fact, if other objects do
> start talking with the downloader object, then the assumption
> can be broken.

In E (I really recommend reading some their stuff at erights.org) you could
make the above perfectly safe. You'd first create a promise like

	def downloadVow := downloader <- download(url)

(see below for the notion of "<-") setup a when-catch block

	when(downloadVow) -> done(doc) {
		println("Done downloading")
	} catch problem {
		println("Download error: " + problem)
	}

and display the your status message here

	println("Downloading " + url).

The interesting part is in the "<-" which creates an "eventual send" that is
guarantueed not to execute before the method you're in is finished. Note
that your argument about "assuming that the downloader is in download state"
does not apply here. You have requested a service (namely to perform the
download) and thus your status message is entirely correct. When the
download completes, it'll display the "done downloading" message (from the
when-catch block) and if it fails for some reason it would print the error
message.

> That seems okay to me.  In fact, I don't see a simple way here
> to have pure transactions -- the whole point is that the downloader
> does some well-defined and predictable thing and then comes back
> later to continue an interrupted discussion.  The objects are
> *collaborating*, and some of the assumptions they make about each
> other involve their current state.

Objects never have to make assumptions about their own state. They _know_
their own state and since it is protected implicitly by the evaluation
mechanisms of the concurrent environment no other object can modify it while
they're performing some service. Making assumptions about other objects
state is - in a concurrent environment - not just bad style but clearly a
bug. If you request a service (see the above example) then again you don't
have to make an assumption about the other objects state. You know that you
_did_ request the download service - the only question is whether it
succeeds or not.

> Overall, for writing threaded programs, I really am sold on using
> message-passing instead of mutexes plus shared stated.  In
> fact, all two times I've written threaded code in Squeak, I used
> a SharedQueue to communicate between the threads.  However, this style
> only makes things easier, not foolproof.  It's still up to the
> programmer to design a good set of messages, and the programmer
> can certainly screw up.

I think nobody will argue over this statement ;-) You can write broken code
in any language and no environment will prevent you doing that. The question
is how much does the environment help you to write correct and well-defined
code without having to resort to introduce an entire extra layer of
simulation?! And that's what I think Ken is after when he's saying that he
wants a language that supports both, sequential and concurrent execution
"primitively".

Cheers,
  - Andreas






More information about the Squeak-dev mailing list