Product Site

12.4.4.1. Semaphores

A semaphore is a mechanism that controls access to resources, for example, preventing simultaneous access. Synchronization often uses semaphores. Here is an example of a semaphore class:
Example 12.8. Example of a Rexx Semaphore Class
/*******************************************************************************/
/*  A Rexx Semaphore Class.                                                    */
/*                                                                             */
/* This file implements a semaphore class in Rexx.  The class is defined to    */
/* the Global Rexx Environment.  The following methods are defined for         */
/* this class:                                                                 */
/*   init - Initializes a new semaphore.  Accepts the following positional     */
/*          parameters:                                                        */
/*                             'name' - global name for this semaphore         */
/*                                if named default to set name in              */
/*                                the class semDirectory                       */
/*                             noshare -  do not define named semaphore        */
/*                                in class semDirectory                        */
/*                             Initial state (0 or 1)                          */
/*   setInitialState - Allow for subclass to have some post-initialization,    */
/*     and do setup based on initial state of semaphore                        */
/*   Waiting  - Is the number of objects waiting on this semaphore.            */
/*   Shared   - Is this semaphore shared (Global).                             */
/*   Named    - Is this semaphore named.                                       */
/*   Name     - Is the name of a named semaphore.                              */
/*   setSem   - Sets the semaphore and returns previous state.                 */
/*   resetSem - Sets state to unSet.                                           */
/*   querySem - Returns current state of semaphore.                            */
/*                                                                             */
/* SemaphoreMeta - Is the metaclass for the semaphore classes.  This class is  */
/*   set up so that when a namedSemaphore is shared, it maintains these        */
/*   named/shared semaphores as part of its state.  These semaphores are       */
/*   maintained in a directory, and an UNKNOWN method is installed on the      */
/*   class to forward unknown messages to the directory.  In this way the      */
/*   class can function as a class and "like" a directory, so [] syntax can    */
/*   be used to retrieve a semaphore from the class.                           */
/*                                                                             */
/*                                                                             */
/* The following are in the subclass EventSemaphore.                           */
/*                                                                             */
/*   Post  - Posts this semaphore.                                             */
/*   Query - Queries the number of posts since the last reset.                 */
/*   Reset - Resets the semaphore.                                             */
/*   Wait  - Waits on this semaphore.                                          */
/*                                                                             */
/*                                                                             */
/* The following are in the subclass MutexSemaphore                            */
/*                                                                             */
/*   requestMutex - Gets exclusive use of semaphore.                           */
/*   releaseMutex - Releases to allow someone else to use semaphore.           */
/*        NOTE: Currently anyone can issue a release (need not be the owner).  */
/*******************************************************************************/
/* ============================================================================ */
/* ===         Start of Semaphore class.                                  ===== */
/* ============================================================================ */
::class SemaphoreMeta subclass class
::method init
  expose semDict
                                            /* Be sure to initialize parent     */
  .message~new(self, .array~of("INIT", super), "a", arg(1,"a"))~send
  semDict = .directory~new

::method unknown
  expose semDict
  use arg msgName, args
                                            /* Forward all unknown messages     */
                                            /* to the semaphore dictionary      */
  .message~new(semDict, msgName, "a", args)~send
  if var("RESULT") then
    return result
  else
    return


::class Semaphore subclass object metaclass SemaphoreMeta

::method init
  expose sem waits shared name
  use arg semname, shr, state

  waits = 0                                 /* No one waiting                   */
  name = ""                                 /* Assume unnamed                   */
  shared = 0                                /* Assume not shared                */
  sem = 0                                   /* Default to not posted            */

  if state = 1 Then                         /* Should initial state be set?     */
    sem = 1
                                            /* Was a name specified?            */
  if VAR("SEMNAME") & semname \= "" Then Do
    name = semname                          /* Yes, so set the name             */


    if shr \= "NOSHARE" Then Do             /* Do we want to share this sem?    */
      shared = 1                            /* Yes, mark it shared              */
                                            /* Shared add to semDict            */
      self~class[name] = self
    End

  End
  self~setInitialState(sem)                 /* Initialize initial state         */

::method setInitialState
                                            /* This method intended to be       */
nop                                         /* overridden by subclasses         */
::method setSem
expose sem
oldState = sem
sem = 1                                     /* Set new state to 1               */
return oldState

::method resetSem
expose sem
sem = 0
return 0

::method querySem
expose sem
return sem


::method shared
expose shared
return shared                               /* Return .true or .false           */

::method named
expose name
                                            /* Does semaphore have a name?      */
if name = "" Then return 0                  /* No, not named                    */
Else return 1                               /* Yes, it is named                 */

::method name
expose name
return name                                 /* Return name or ""                */

::method incWaits
expose waits
waits = waits + 1                           /* One more object waiting          */

::method decWaits
expose Waits
waits = waits - 1                           /* One object less waiting          */

::method Waiting
expose Waits
return waits                                /* Return number of objects waiting */
/* ========================================================================== */
/* ===         Start of EventSemaphore class.                             === */
/* ========================================================================== */

::class EventSemaphore subclass Semaphore public
::method setInitialState
  expose posted posts
  use arg posted

  if posted  then posts = 1
  else posts = 0
::method post
  expose posts posted

  self~setSem                        /* Set semaphore state            */
  posted = 1                         /* Mark as posted                 */
  reply
  posts = posts + 1                  /* Increase the number of posts   */

::method wait
  expose posted

  self~incWaits                      /* Increment number waiting       */
  guard off
  guard on when posted               /* Now wait until posted          */
  reply                              /* Return to caller               */
  self~decWaits                      /* Cleanup, 1 less waiting        */

::method reset
  expose posts posted

  posted = self~resetSem             /* Reset semaphore                */
  reply                              /* Do an early reply              */
  posts = 0                          /* Reset number of posts          */

::method query
  expose posts
                                     /* Return number of times         */
  return posts                       /* Semaphore has been posted      */
/* ========================================================================== */
/* ===         Start of MutexSemaphore class.                             === */
/* ========================================================================== */

::class MutexSemaphore subclass Semaphore public

::method setInitialState
  expose owned
  use arg owned


::method requestMutex
  expose Owned

  Do forever                                /* Do until we get the semaphore  */
    owned = self~setSem
    if Owned = 0                            /* Was semaphore already set?     */
      Then leave                            /* Wasn't owned; we now have it   */
    else Do
      self~incWaits
      guard off                             /* Turn off guard status to let   */
                                            /* others come in                 */
      guard on when \Owned                  /* Wait until not owned and get   */
                                            /* guard                          */
      self~decWaits                         /* One less waiting for MUTEX     */
    End
                                            /* Go up and see if we can get it */
  End


::method releaseMutex
  expose owned
  owned = self~resetSem                     /* Reset semaphore                */

Note

See also semaphore classes EventSemaphore Class and MutexSemaphore Class.