[BUG] Crash while working on a Future.

Michael van der Gulik squeakml at gulik.co.nz
Sat Jun 24 04:39:26 UTC 2006


Hi Tom (and others)

Tom Phoenix wrote:

>> Run "Future doing: [ByteString]" to crash the image.
> 
> 
> Does it have to be ByteString? That's an important class in the
> system. It seems to be an arbitrary choice, since it only shows up in
> your halt code.

It was arbitrary; it was the only case I tried because it was the one 
that I originally found to crash the image.

> As I understand the operation of #becomeForward:, you're
> instantaneously turning your MessageCapture instance into ByteString.
> But the identity hash of your instance should stay the same, in case
> it's in a dictionary, say. That means that the identity hash of
> ByteString changes to become the hash of your object, even though that
> can break any dictionaries that *it* was in.

I consider that a bug in becomeForward:. I've just done some 
experimentation:

a := Object new.
b := Object new.
a hash   414
b hash   1169
a becomeForward: b copyHash: true.
a hash  414
b hash  414  "b's hash just got clobbered"

a := Object new.
b := Object new.
a hash  966
b hash  1534
a becomeForward: b copyHash: false.
a hash  1534  "IMO this should be the default."
b hash  1534

a := Object new.
b := Object new.
a hash  2248
b hash  2955
a becomeForward: b.
a hash  2248
b hash  2248  "b's hash just got clobbered"

So it seems by default that #becomeForward: copys the hash by default.

In my opinion, this is very broken. I use becomeForward:, assuming that 
every reference to "a" really does become a reference to "b" and that 
"b" won't suddenly have any unexpected state changes (ESPECIALLY a 
change in hash!).

My code shouldn't break (when it's bug free :-) ) because if "a" gets 
included in any dictionaries, a dictionary implementation will send the 
#hash message, which will wait on the semaphore in doesNotUnderstand: in 
"a" until "a" has becomeForwarded to "b". The #hash message should then 
return with the correct hash.

I assume, of course, that becomeForward: will also change any references 
in MethodContexts correctly.

> Maybe a subclass of ProtoObject and wizardly uses of #become: isn't
> the technology you need to use. Have I understood correctly what
> you're trying to do? It seems to me that you want an object that is a
> placeholder today and the real value tomorrow. 

Yup. It's called a "future" :-). If I remember correctly, its a pattern 
used for concurrent applications, although evidently not a simple one to 
implement.


> That's probably
> possible without much magic. But you must ensure that a client doesn't
> send messages to the placeholder before it becomes the real value. I
> don't see any good way to do that without asking the client to do
> something active, such as using a Semaphore, or sending the
> placeholder a signal. The trouble I see is that there's no way to tell
> when a message to the placeholder is "really" destined for the real
> value.

I agree that a better and more robust solution would not involve using 
ProtoObjects. Infact, an even better solution would be to look at the 
bigger picture and try not to use Futures at all.

> 
> Here's some brainstorming....
> 
>  "A client wants to do something while a calculation completes"
>  nilNowValLater := Future doing: [ 49 sqrt ].
>  nilNowValLater inspect. "It's nil, maybe still"
>  self doSomething.
>  [ nilNowValLater isNil ] whileTrue. "Bad: Busy wait"
>  nilNowValLater inspect. "Now it's 7"
> 
> The busy wait is undesirable, since we tie up the processor precisely
> when we want it to devote time to the other process. We could put in a
> Delay, but let's try a different way.

A semaphore would be better here.

>  stat := Future doing: [ 49 sqrt ].
>  stat inspect. "It's an instance of Future"
>  self doSomething.
>  stat isDone ifFalse: [ self doSomethingMore ].
>  stat result inspect. "gives 7"

This is a better way of doing things.

> Under this metaphor, an instance of Future is the status of the
> request, and you have to ask it for the result. Ask whenever you'd
> like, but you may have to wait for the answer, if it's not ready yet.
> Nothing magically updates, so I don't have to deal with any new
> concepts. And it allows code like this:
> 
>  "Open an inspector as soon as the network request has returned a value."
>  stat := Future doing: [ networkRequest value ].
>  stat whenDoneDo: [:result | result inspect ].
> 
>  "If time runs out, return a failureToken"
>  stat afterTimeoutSeconds: 300 terminateAndDo: [ stat return: self
> failureToken ].
> 
>  "Another way to handle time-out: cancel the inspection"
>  stat afterTimeoutSeconds: 300 terminateAndDo: [ stat abort ].
> 
> This seems like a fairly clean and flexible model that would be
> relatively easy to implement. Would something like that work for you?

Potentially; in either case it is certainly a very useful concept. I'm 
going to have to refactor my code anyway, so I'll see if I can get rid 
of my Futures altogether.

> Hope this helps!

Mentioning the hash stuff certainly did! Many thanks for that.

Mikevdg.




More information about the Squeak-dev mailing list