BoltLock.st
changeset 2801 c1ed819bc4a9
parent 2799 25cf016d4eed
child 2802 3cadee07e98f
--- 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!