eXept Software AG Logo

Smalltalk/X Webserver

Documentation of class 'BoltLock':

Home

Documentation
www.exept.de
Everywhere
for:
[back]

Class: BoltLock


Inheritance:

   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

Description:


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.

copyright

COPYRIGHT (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 protocol:

class initialization
o  initialize
(comment from inherited method)
called only once - initialize signals

instance creation
o  new
return an initialized instance


Instance protocol:

initialization
o  initialize
Invoked when a new instance is created.

waiting
o  release
release the lock

Usage example(s):

Transcript showCR:'  release in state ',state.

o  waitForRead
wait for the lock in order to read

Usage example(s):

Transcript showCR:'  waitForRead in state ',state.

o  waitForWrite
wait for the lock in order to read

Usage example(s):

Transcript showCR:'  waitForWrite in state ',state.


Examples:


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].


ST/X 7.7.0.0; WebServer 1.702 at 20f6060372b9.unknown:8081; Mon, 18 Nov 2024 05:50:37 GMT