--- a/BoltLock.st Mon Aug 06 16:32:56 2012 +0200
+++ b/BoltLock.st Mon Aug 06 17:12:30 2012 +0200
@@ -13,7 +13,7 @@
Object subclass:#BoltLock
instanceVariableNames:'state numReaders waitingProcesses name'
- classVariableNames:'StateFree StateLocked StateBusy'
+ classVariableNames:'StateFree StateLocked StateBusy StateWantLock'
poolDictionaries:''
category:'Kernel-Processes'
!
@@ -49,9 +49,10 @@
C; locked - a single writer has the lock; no other reader or writer is allowed
to aquire it
- [caveat:]
- with many readers, the writers tend to make only very slow progress
- (need priority based wakeup).
+ [notice:]
+ the original BoldLock was unfair in that new incoming readers could lock up a waiting writer.
+ This has been fixed by adding a fourth state (wantToLock), which is set by a write-waiter to prevent
+ new readers from getting the lock.
[instance variables:]
state <Symbol>
@@ -78,7 +79,7 @@
"
many processes synchronizing on a boltLock:
[exBegin]
- |lock readers readWriters|
+ |lock readers readWriters currentWriter processes|
lock := BoltLock new.
@@ -88,14 +89,18 @@
(Random nextIntegerBetween:1 and:6) == 1 ifTrue:[
Transcript showCR:('thread %1: want to write...' bindWith:tNo).
lock waitForWrite.
+ currentWriter notNil ifTrue:[Transcript showCR:('ouch %1: writer is %2' bindWith:tNo with:currentWriter).self halt].
+ currentWriter := tNo.
Transcript showCR:('thread %1: **** write' bindWith:tNo).
Delay waitForSeconds:(Random nextIntegerBetween:1 and:4).
Transcript showCR:('thread %1: done writing.' bindWith:tNo).
+ currentWriter := nil.
lock release.
Delay waitForSeconds:(Random nextIntegerBetween:1 and:4).
] ifFalse:[
Transcript showCR:('thread %1: want to read...' bindWith:tNo).
lock waitForRead.
+ currentWriter notNil ifTrue:[Transcript showCR:('ouch %1: writer is %2' bindWith:tNo with:currentWriter).self halt].
Transcript showCR:('thread %1: ---- read' bindWith:tNo).
Delay waitForSeconds:(Random nextIntegerBetween:1 and:4).
Transcript showCR:('thread %1: done reading.' bindWith:tNo).
@@ -112,6 +117,7 @@
10 timesRepeat:[
Transcript showCR:('thread %1: want to read...' bindWith:tNo).
lock waitForRead.
+ currentWriter notNil ifTrue:[Transcript showCR:('ouch %1: writer is %2' bindWith:tNo with:currentWriter).self halt].
Transcript showCR:('thread %1: ---- read' bindWith:tNo).
Delay waitForSeconds:(Random nextIntegerBetween:1 and:4).
Transcript showCR:('thread %1: done.' bindWith:tNo).
@@ -122,6 +128,7 @@
] newProcess name:('r%1' bindWith:tNo).
].
+ processes := readWriters , readers.
readWriters do:[:t | t resume].
readers do:[:t | t resume].
[exEnd]
@@ -142,6 +149,7 @@
StateFree := #free.
StateBusy := #busy.
StateLocked := #locked.
+ StateWantLock := #wantLock.
"Created: / 06-08-2012 / 15:49:44 / cg"
! !
@@ -230,7 +238,7 @@
|activeProcess wasBlocked|
wasBlocked := OperatingSystem blockInterrupts.
- "/ Transcript showCR:' release in state ',state.
+ Transcript showCR:' release in state ',state.
activeProcess := Processor activeProcess.
state == StateLocked ifTrue:[
"I am the writer"
@@ -259,8 +267,8 @@
wasBlocked := OperatingSystem blockInterrupts.
- "/ Transcript showCR:' waitForRead in state ',state.
- state == StateLocked ifTrue:[
+ Transcript showCR:' waitForRead in state ',state.
+ (state == StateFree or:[state == StateBusy]) ifFalse:[
"being written; wait until released"
activeProcess := Processor activeProcess.
[
@@ -274,7 +282,7 @@
wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
].
self removeWaitingProcess:activeProcess.
- ] doUntil:[ state ~~ StateLocked].
+ ] doUntil:[ state == StateFree or:[state == StateBusy] ].
].
numReaders := numReaders + 1.
@@ -292,9 +300,14 @@
wasBlocked := OperatingSystem blockInterrupts.
- "/ Transcript showCR:' waitForWrite in state ',state.
+ Transcript showCR:' waitForWrite in state ',state.
state ~~ StateFree ifTrue:[
"being read or written"
+ state == StateBusy ifTrue:[
+ "/ no new readers
+ state := StateWantLock
+ ].
+
activeProcess := Processor activeProcess.
[
self addWaitingProcess:activeProcess.
@@ -320,11 +333,11 @@
!BoltLock class methodsFor:'documentation'!
version
- ^ '$Header: /cvs/stx/stx/libbasic2/BoltLock.st,v 1.2 2012-08-06 14:32:26 cg Exp $'
+ ^ '$Header: /cvs/stx/stx/libbasic2/BoltLock.st,v 1.3 2012-08-06 15:12:30 cg Exp $'
!
version_CVS
- ^ '$Header: /cvs/stx/stx/libbasic2/BoltLock.st,v 1.2 2012-08-06 14:32:26 cg Exp $'
+ ^ '$Header: /cvs/stx/stx/libbasic2/BoltLock.st,v 1.3 2012-08-06 15:12:30 cg Exp $'
! !
BoltLock initialize!