Interesting Locking Problem

Ross Boylan RossBoylan at stanfordalumni.org
Fri Mar 29 00:02:21 UTC 2002


I have two smalltalk processes that sometimes write the same
data. Further, each process may write recursively; in the course of
handling one write, it will attempt other writes.  I need to permit
the recursive writes within a process while blocking activity between
the processes.

I would appreciate advice about how best to do this.  My current
approach has a small vulnerability, and it's not clear to me how to
correct it.  Further, it already seems a bit elaborate.

I implement locking on the class side of one of my classes:
lock
	"Acquire a Lock for the invoking Process, waiting as necessary"
	[ProcessLock notNil and: [ProcessLock ~~ Processor activeProcess]] whileTrue: [
		(Delay forMilliseconds: 300) wait.
		].
	ProcessLock _ Processor activeProcess.
	UpdateLocks _ UpdateLocks ifNil: [1] ifNotNil:[UpdateLocks+1].

The ProcessLock class variable permits the original process to get
recursive locks, and the UpdateLocks variable keeps track of when
we're really done.

unlock
	"Permit activity in the update process"
	self assert: [UpdateLocks > 0].  "and it should not be nil"
	self assert: [ProcessLock == Processor activeProcess].
	UpdateLocks _ UpdateLocks-1.
	UpdateLocks = 0 ifTrue: [
		ProcessLock _ nil.
		]

The problem is that these operations need to be atomic and they
aren't.  For example, in lock ProcessLock might test as nil, but then
the other process might reset it before the first process does.  For
the truly paranoid, even UpdateLocks _ UpdateLocks-1 is not safe
(maybe it is, given the VM, but I don't know that).

I thought of adding a Semaphore and using critical: to protect the
entire method, but this could lead to deadlock:
Process A sets the ProcessLock (waiting and then signalling the semaphore).
Process B enters the critical section, but does not exit it since
	it is in the loop waiting for ProcessLock to be nil)
Process A attempts a recursive write operation.  It begins by 
	invoking the lock method, which waits on the semaphore.
	Since B has not finished its critical section, there
	are no spare signals, so A is blocked.

For one of the processes there is a natural place to use a top-level
lock, but for the other there is not; hence the need to deal with
recursion.  I suppose if I could restructure it to get a top level for
the other process I could use a conventional mutex and be done.  Any
other ideas?



More information about the Squeak-dev mailing list