|
Class: BoltLock
Object
|
+--AbstractLock
|
+--BoltLock
- Package:
- stx:libbasic2
- Category:
- Kernel-Processes
- Version:
- rev:
1.13
date: 2024/01/29 20:43:51
- user: cg
- file: BoltLock.st directory: libbasic2
- module: stx stc-classLibrary: libbasic2
A BoltLock (aka BoltVariable) is a 3-state semaphore,
useful to protect a resource against single writers, while allowing multiple
readers to access the resource simultaneously.
The lock is in one of 3 states:
A; free - can be changed by a writer into the locked state,
or by a reader into the busy state.
B; busy - can only be entered by another reader. left into free by last reader.
C; locked - a single writer has the lock;
no other reader or writer is allowed to acquire it
[notice:]
the original BoltLock 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>
numReaders <Integer> number of readers holding onto the lock
waitingProcesses <OrderedCollection> waiting processes - will be served first
come first served when signalled.
name <String> a debugging aid: an optional userFriendly
name; helps to identify a semaphore easier.
copyrightCOPYRIGHT (c) 2012 by Claus Gittinger
All Rights Reserved
This software is furnished under a license and may be used
only in accordance with the terms of that license and with the
inclusion of the above copyright notice. This software may not
be provided or otherwise made available to, or used by, any
other person. No title to or ownership of the software is
hereby transferred.
class initialization
-
initialize
-
(comment from inherited method)
called only once - initialize signals
instance creation
-
new
-
return an initialized instance
initialization
-
initialize
-
Invoked when a new instance is created.
waiting
-
release
-
release the lock
Usage example(s):
Transcript showCR:' release in state ',state.
|
-
waitForRead
-
wait for the lock in order to read
Usage example(s):
Transcript showCR:' waitForRead in state ',state.
|
-
waitForWrite
-
wait for the lock in order to read
Usage example(s):
Transcript showCR:' waitForWrite in state ',state.
|
many processes synchronizing on a BoltLock:
|lock visualizeStream eventStream readers readWriters currentWriter visualizer holder label|
lock := BoltLock new.
visualizeStream := InternalPipeStream new.
eventStream := SplittingWriteStream on:visualizeStream and:Transcript.
readWriters := (1 to:10) collect:[:tNo |
[
10 timesRepeat:[
(Random nextIntegerBetween:1 and:6) == 1 ifTrue:[
eventStream synchronized:[eventStream showCR:('thread %1: wants to write...' bindWith:tNo)].
lock waitForWrite.
currentWriter notNil ifTrue:[eventStream showCR:('ouch %1: writer is %2' bindWith:tNo with:currentWriter).self halt].
currentWriter := tNo.
eventStream synchronized:[eventStream showCR:('thread %1: **** write' bindWith:tNo)].
Delay waitForSeconds:(Random nextIntegerBetween:1 and:4).
eventStream synchronized:[eventStream showCR:('thread %1: done writing.' bindWith:tNo)].
currentWriter := nil.
lock release.
Delay waitForSeconds:(Random nextIntegerBetween:1 and:4).
] ifFalse:[
eventStream synchronized:[eventStream showCR:('thread %1: wants to read...' bindWith:tNo)].
lock waitForRead.
currentWriter notNil ifTrue:[eventStream synchronized:[eventStream showCR:('ouch %1: writer is %2' bindWith:tNo with:currentWriter).self halt]].
eventStream synchronized:[eventStream showCR:('thread %1: ---- read' bindWith:tNo)].
Delay waitForSeconds:(Random nextIntegerBetween:1 and:4).
eventStream synchronized:[eventStream showCR:('thread %1: done reading.' bindWith:tNo)].
lock release.
Delay waitForSeconds:(Random nextIntegerBetween:1 and:4).
].
].
eventStream synchronized:[eventStream showCR:('thread %1: finished.' bindWith:tNo)].
] newProcess name:('rw%1' bindWith:tNo).
].
readers := (11 to:20) collect:[:tNo |
[
10 timesRepeat:[
eventStream synchronized:[eventStream showCR:('thread %1: wants to read...' bindWith:tNo)].
lock waitForRead.
currentWriter notNil ifTrue:[eventStream synchronized:[eventStream showCR:('ouch %1: writer is %2' bindWith:tNo with:currentWriter).self halt]].
eventStream synchronized:[eventStream showCR:('thread %1: ---- read' bindWith:tNo)].
Delay waitForSeconds:(Random nextIntegerBetween:1 and:4).
eventStream synchronized:[eventStream showCR:('thread %1: done.' bindWith:tNo)].
lock release.
Delay waitForSeconds:(Random nextIntegerBetween:1 and:4).
].
eventStream synchronized:[eventStream showCR:('thread %1: finished.' bindWith:tNo)].
] newProcess name:('r%1' bindWith:tNo).
].
visualizer := ModalBox label:'BoltLock Example'.
visualizer add:(Label label:(e'waiting to read\nreading\nwaiting to write\nwriting'
emphasis:(RunArray new add:#bold withOccurrences:15; add:nil; add:{#color->Color blue. #bold} withOccurrences:7; add:nil; add:{#color->Color orange. #bold} withOccurrences:16; add:nil; add:{#color->Color red. #bold} withOccurrences:7; yourself)))
at:(0 @ 30).
holder := '1 2 3' asValue.
label := Label new labelChannel:holder; yourself.
visualizer add:label.
[visualizer open] fork.
[
|queue finished rxIndex rxEvent textStream line|
queue := OrderedCollection new.
rxIndex := '\d+' asRegex.
rxEvent := '\:[\s|\S]+' asRegex.
finished := 0.
textStream := WriteStream on:Text new.
[finished < 20] whileTrue:[
line := visualizeStream nextLine.
line isNil ifTrue:[
Delay waitForMilliseconds:50.
]ifFalse:[
|index event|
index := (rxIndex matchesIn:line) first.
event := (rxEvent matchesIn:line) first.
(event = ': wants to read...') ifTrue:[
queue add:index allBold.
].
(event = ': wants to write...') ifTrue:[
queue add:(index allBold withColor:(Color orange)).
].
(event = ': done.' or:[event = ': done reading.'] or:[event = ': done writing.']) ifTrue:[
queue remove:index.
].
(event = ': ---- read') ifTrue:[
queue detect:[:t| t = index] thenCompute:[:t| t colorizeAllWith:Color blue].
].
(event = ': **** write') ifTrue:[
queue detect:[:t| t = index] thenCompute:[:t| t colorizeAllWith:Color red].
].
(event = ': finished.') ifTrue:[
finished := finished + 1.
].
textStream clear.
queue do:[:t| textStream nextPutAll:t; nextPut:$ .].
holder value:textStream contents.
].
].
holder value:'example finished'
] forkNamed:'Visalizer'.
readWriters do:[:t | t resume].
readers do:[:t | t resume].
|
|