[Q] Has SharedQueue a very subtle bug?

Scott A Crosby crosby at qwes.math.cmu.edu
Sat Apr 13 04:12:38 UTC 2002

On Fri, 12 Apr 2002 goran.hultgren at bluefish.se wrote:

> I have been looking at #size and #isEmpty in SharedQueue. Those two
> methods are not protected by the accessProtect Semaphore. Since I don't
> really know that much about Squeak Process scheduling, my question is:

> Could another Process call #size or #isEmpty when the first Process is
> at the exact point marked below:

If you assume concurrent accesses, which you want to be robust with..
You need to use those when the semaphore is held.. Something like

queue runWithLockAndSize: [ :size | ...... ]           [1]
queue runWithLockIfEmpty: [  ..... ]

And the blocks are not allowed to do any queue operations. (unless we give
squeak the ability to have recursive locks.)

Or allow:

queue runWithLock: [  .... can run various unprotected operations on the
queue, but cannot run any enqueue/dequeue operations on *this* queue .... ]


The bug you describe exists, #size and #ifEmpty, as written, is unusable
except as a potentially inaccurate approximation.. (I needed to activate
various semaphores based on the size of the queue. Thus I needed a
operation akin to [3].)

IE, I needed something like:

queue size > HighWaterMark & self enabled ifTrue: [ disable something]
queue size < LowWaterMark & self disabled ifTrue: [ enable something]

And you can't get an *accurate* size outside the lock on the semaphore.
#peek below just means that we run a risk of an inaccurate and possibly
corrupt size. If #size also got #accessProtect, we'd still have this

For example, what should the value of 'a' be after this runs?

q Sharedqueue new.
a Array new: 2.

[[ q nextPut: 1 ; next ] repeatForever] fork.
[[ a at: q size put: (a at: q size)+1] repeatForever] fork.

"Now run both of them for a minute."


> peek
> =09"Answer the object that was sent through the receiver first and
> has not
> =09yet been received by anyone but do not remove it from the receiver. If
> =09no object has been sent, suspend the requesting process until one is."
> =09| value |
> =09accessProtect
> =09=09critical: [readPosition >=3D writePosition
> =09=09=09=09=09ifTrue: [readPosition _ 1.
> ************HERE*************
> =09=09=09=09=09=09=09writePosition _ 1.
> =09=09=09=09=09=09=09value _ nil]
> =09=09=09=09=09ifFalse: [value _ contentsArray at: readPosition]].
> =09^value
> Since I believe this is so I would say that #size could potentially give
> a rather large incorrect answer when the queue is in fact empty (which
> could cause that process to try to read the queue and block). #isEmpty
> could also answer false when it is in fact true.
> I tried to provoke this error but failed - my testcode might have been
> wrong. I know this might be "nitpicking" but I am curious and if it is
> indeed a bug it could save someone hours of debugging chasing this down
> - it wouldn't happen very often...
> regards, G=F6ran

No DVD movie will ever enter the public domain, nor will any CD. The last C=
and the last DVD will have moldered away decades before they leave copyrigh=
This is not encouraging the creation of knowledge in the public domain.

More information about the Squeak-dev mailing list