class ref name: semaphore
category-group: os
layer: 0
header file: z_semaphore.h

synopsis.
the semaphore_o class provides for a means of protecting access to an object. It is primarily used in conjunction with threaads (see the threaad_o ) class. Z Directory semaphores are comprised of a semaphore_o class and sub-classes that implement the semaphore. Currently there are 2 implementations: the "operating system", and a pure software-based solution by Eisenberg & McGuire . The latter has a maxiumum limit of 10 threads per semaphore.

There are many different implemenations of semaphores. Typically, the underlying OS provides an implementation - we recommend using the OS's.

The number of member functions of class semaphore_o is fewer than may appear at first glance - several functions are aliases. That is, they are alternate names for the same function:

base function alias function description
enter() wait(), down()
leave() release(), up()
There are other names that can be used for these operations. The most famous would be Dijkstra's P() (enter()) and V() (leave()). Other possibilities for enter() include block(), plantinga(), probeer() (or proberen()); and for leave(), include signal(), increment(), vegter() (or verogen()), and verhoog(). The non-English nomenclature is Dutch, courtesy of E. W. Dijkstra.

description.
whenever you want to have access to a particular item or resource that must or should be accessed one at a time, the process or thread accesses a singleton, global semaphore that "guards" the item. Prior to access, call the semaphores's "enter()" function, and when done, call the semaphores's "leave()" function. Internally, the semaphore maintains a count of all threads accessing it. 'Entering' decrements the counter and leaving increments it. If the counter is 0, the thread blocks, waiting for the item to be freed, via a leave by another thread.

There are a number of popular pairs of function names used to denote requesting access and releasing access:

    up(), down();
    enter(), leave();
    wait(), realease() [or post()];
    P(), V();
All of these except "post()" and the last (Djikstra's "P/V") are provided by this object. The default is "enter()" and "leave()". You can choose any (or even mix and match), as desired.

member functions (primary)

semaphore_o()
SIGNATURE: semaphore_o ()
SYNOPSIS:
creates a a new semaphore object. The semaphore will be implemented as the default implementation ("zstyle_Semaphore_Default"). The up/down value will be initialized to 0.
 

semaphore_o(<args>)
SIGNATURE: semaphore_o (z_Semaphore_Style x)
SYNOPSIS:
This constructor instantiates a new semaphore, implemented according to the value of "x". The up/down value will be initialized to 0.
 

destructor
SIGNATURE: ~semaphore_o ()
SYNOPSIS: destroys thesemaphore object instance. Any accessor values are "released".
 

value()
SIGNATURE: int value()
SYNOPSIS: returns the number of threads currently requesting access to the semaphore object.
RETURNS: [n]: number of current "requestors" (n >= 0)
 

enter()
SIGNATURE: int enter()
SYNOPSIS:
requesting access to the semaphore. If the semaphore is "busy" (the accessor count is 1 or more), the thread or process-program will block until the count goes to 0. The count will be decremented by 1 after this function call.
The following member functions are equivalent to enter(). [they are implemented by simply calling "enter()"]:

    int down();
    int wait();

RETURNS: [n]: number of current "requestors" (n >= 0)
 

leave()
SIGNATURE: int leave()
SYNOPSIS:
informs the semaphore that the thread or process no longer needs it. The number of threads currently requesting access is incremented.
The following member functions are synonymous with "leave()" [they are implemented by simply calling "leave()"]:

    int up();
    int release();

RETURNS: [n]: number of current "requestors" (n >= 0)
 

gap()
SIGNATURE: int gap()
SYNOPSIS: decrements the current semaphore count without blocking. This is similar to calling "enter()",
 

note.
The semaphore class employs a handle-body idiom. The class is designed to accomodate multiple subclasses. If a new sub-class [implementation] is to be added, however, the semaphore_o header file will need to be modified.

examples.
With seamphores, there is very little code to show for an example. In this example, a global variable "popular_var" is protected by a semaphore object. No threads are involved, to keep things simple. Note that global-scope class object instances are generally undesirable - you should use a pointer to an object, if it is a global. This is done in the code below, for the global semaphore object "ps".

#include "z_types.h"
#include "z_semaphore.h"

static int popular_var = 7;
semaphore_o *ps = NULL;

static void access_action(boolean = TRUE);

int main ()
{
    ps = new semaphore_o;
    if (ps == NULL) exit(1);

    access_action(TRUE);        // this function typically might be
    access_action(FALSE);       // called repeatedly by various threads
    access_action(TRUE);
    access_action(TRUE);
    access_action(FALSE);
    std::cout << "the final value is: " << popular_var << std::endl;
    exit(0);
}

static void access_action (boolean raise)
{
    ps->enter();                // LIMIT ACCESS TO THE VAR "popular_var"
    if (raise)
        popular_var += 4;
    else
        popular_var -= 3;
    ps->leave();                // LEAVING - PERMIT OTHER THREADS TO ACCESS IT
}