gc and synchronization, Weak Array..

Peter Smet peter.smet at flinders.edu.au
Wed May 12 07:45:12 UTC 1999


Bob,

 Thanks for ferreting this problem out. In some of my own debugging I also
noticed
 that arrays that I was inspecting had turned to nil (nil ), so I thought
there was
 a problem with the finalizationProcess running concurrently. I deliberately
created and removed stacks of new Objects to stress-test the whole thing.


On Tue, 11 May 1999 14:08:55 +0930 "Peter Smet" <peter.smet at flinders.edu.au>
wrote:
>Today Peter Smet Re: gc and synchronization, Weak Array..
>
>   The other thing that I didnt realise, which Andreas pointed out, is that
>no process can interupt
>   a critical: section. I assumed that only processes waiting for that
>particular semaphore couldnt
>   interupt...

Well, I think you had it right the first time. Contrast the behavior of the
following:

| done accessSema |
done _ false.
accessSema _ Semaphore forMutualExclusion.
[[done] whileFalse: [1 beep. (Delay forSeconds: 2) wait]] forkAt: 6.
accessSema critical: [[Sensor anyButtonPressed] whileFalse: []].
done _ true.

with:

| done accessSema |
done _ false.
accessSema _ Semaphore forMutualExclusion.
[[done] whileFalse: [accessSema critical: [1 beep]. (Delay forSeconds: 2)
wait]] forkAt: 6.
accessSema critical: [[Sensor anyButtonPressed] whileFalse: []].
done _ true.

In the first, the machine keeps beeping. In the second, it only beeps twice.
You would still need a #critical: sent to the same semaphore in both
processes to keep things civilized.


   Ok then things do work as I expected them to.  Thanks for getting that
straight...

I also ran your code with some debugging stuff added. Whenever
WeakKeyDictionary>>finalizeValues was run, I saved a stack trace on the
other process. When the test crashed, here is what I saw during the last
finalization:

WeakKeyAssociation>>key:
WeakKeyAssociation class(LookupKey class)>>key:
WeakKeyAssociation class(Association class)>>key:value:
WeakKeyDictionary>>at:put:
[] in PostOffice>>at:at:
WeakKeyDictionary(Dictionary)>>at:ifAbsent:
PostOffice>>at:at:
PostOffice>>at:at:at:
PostOffice>>when:send:to:for:
Bag(Object)>>when:send:to:withAll:
[...]

WeakKeyDictionary>>at:put: is

at: key put: anObject
"Set the value at key to be anObject.  If key is not found, create a new
entry for key and set is value to anObject. Answer anObject."
| index element |
key isNil ifTrue:[^anObject].
index _ self findElementOrNil: key.
element _ array at: index.
element == nil
ifTrue: [self atNewIndex: index put: (WeakKeyAssociation key: key value:
anObject)]
ifFalse: [element value: anObject].
^ anObject

So, the main process had already determined an index at which to add a new
association and was just about to do that when the WKD was finalized, thus
shrinking the collection so that the index was no longer valid. Note that it
also could happen that the index would still be valid, in which case you
would merely (!) insert the association in the wrong place.

In short, there seem to be two choices:
1. Use a Semaphore>>critical: for *all* routines that access (not just
update) a given collection.
2. Keep all accesses in one process by making the removal of nil keys a
responsibility of those doing the accessing.


    I was thinking of giving WKD a mutex, and that essentially everything
will pass through that (ie soln 1).
   As I said in my last post, a Synchronizing Wrapper class would be the
most flexible. Havent had time to    actually implement it yet.... Dolphin
had a great wrapper generator tool that takes 95% of the tedium out
of doing wrappers, but it is not ported to Squeak.

   Thanks again for the posts, they have been really helpful!

Peter





More information about the Squeak-dev mailing list