Contents

Class Semaphore


Inheritance:

Object  »
  Collection  »
    SequenceableCollection  »
      LinkedList  »
        Semaphore

A Semaphore provides synchronized communication of a single bit of information (a "signal") between Processes. A signal is sent by sending the message signal and received by sending the message wait. If no signal has been sent when a wait message is sent, the sending Process will be queued to wait for a signal that permits continuation.

A semaphore maintains a counter of excess signals and a queue of waiting processes. It stores and forwards permissions to continue process execution and it halts processes that need a permission that was still not given.

Semaphore is a subclass of LinkedList. The inherited functionality of LinkedList is used to queue waiting processes.

A semaphore lives in the Smalltalk image; it is not mapped to a semaphore of your computer's operating system. A primitive can have access to a semaphore that is registered in slot 39 of the special objects array (see the class protocol of class ExternalObjectsTable for details of doing that).

Instance Variables:

Class Methods

Instance methods

Example of Use:

A semaphore can be used to implement exclusive access to a variable:

  | variable sema |
sema := Semaphore forMutualExclusion.

sema critical: [variable := <an expression>].

sema critical: [self use: variable].

Blocks that are provided as an argument to Semaphore>>critical: should have robust exception handling. For blocks that do not handle exceptions, the use of Semaphore>>critical:ifError: is recommended. That method ensures that exception handling occurs after mutual exclusion is left.

Mutual exclusion ensures that at most one process enters the critical region. It does not ensure that all expressions of the critical region are always evaluated. The following example demonstrates that

Object subclass: #TwoItems
    instanceVariableNames: 'firstItem secondItem'
     classVariableNames: ''
     poolDictionaries: ''
     category: 'Squeak Peculiarities'
initialize
  firstItem := secondItem := 0.

This class uses three simple methods to initialize its instance variables and to increment them:

incFirst
  firstItem := firstItem + 1.
incSecond
  secondItem := secondItem + 1.

Now we can write:

  | protectedObject
    mutualExclusionSema yieldSema goon 
    workerProcess terminator |

mutualExclusionSema := Semaphore forMutualExclusion.
yieldSema := Semaphore new.
goon := Semaphore new.

protectedObject := TwoItems new.

workerProcess :=
   [mutualExclusionSema
         critical: 
            [protectedObject incFirst.
             yieldSema signal.
             protectedObject incSecond. ].
   ] newProcess.
terminator :=
   [yieldSema wait. workerProcess terminate. goon signal.]
       newProcess.

terminator priority: Processor timingPriority ; resume.
workerProcess resume.

goon wait.
protectedObject inspect

We see that only one of the variables in the protected object was incremented.


Contents