A semaphore is a synchronization mechanism similar to a
mutex or a machine interface (MI) lock. It can be used to control access to
shared resources, or used to notify other threads of the availability of
resources. It differs from a mutex in the following ways:
- A semaphore set is not a single value, but has a set of values. It is
referred to through a semaphore set containing multiple
semaphores. Each semaphore set is identified by a semid, which
identifies the semaphore set, and a semnum, which identifies the
semaphore within the set. Multiple semaphore operations may be specified on one
semop() call. These operations are atomic on multiple
semaphores within a semaphore set.
- Semaphore values can range from 0 to 65535.
- Semaphores have permissions associated with them. A thread
must have appropriate authorities to perform an operation on a semaphore.
- A semaphore can have a semaphore adjustment value
associated with it. This value represents resource allocations which can be
automatically undone by the system when the thread ends, representing the
releasing of resources. The adjustment value can range from -32767 to
32767.
Thus, a semaphore can be used as a resource counter or as a lock.
A process gets a semaphore set identifier by calling the
semget() function. Depending on the key and semflg
parameters passed in, either a new semaphore set is created or an existing
semaphore set is accessed. When a new semaphore set is created, a data
structure is also created to contain information about the semaphore set. This
structure is defined in the <sys/sem.h> header file as
follows:
typedef struct semid_ds {
struct ipc_perm sem_perm; /* Permissions structure */
unsigned short sem_nsems; /* Number of sems in set */
time_t sem_otime; /* Last sem op time */
time_t sem_ctime; /* Last change time */
} semtablentry_t;
A thread performs operations on one or more of the semaphores in a set by
calling the semop() function. The following parameters are
passed in:
- Semaphore ID
- Pointer to an array of sembuf structures
- Number of sembuf structures in the array.
The sembuf structure is defined in the
<sys/sem.h> header file as follows:
struct sembuf {
unsigned short sem_num; /* Semaphore number */
short sem_op; /* Semaphore operation */
short sem_flg; /* Operation flags */
};
The operation performed on a semaphore is specified by the sem_op
field, which can be positive, negative, or zero:
- If sem_op is positive, the value of sem_op is added to
the semaphore's current value.
- If sem_op is zero, the caller will wait until the semaphore's
value becomes zero.
- If sem_op is negative, the caller will wait until the semaphore's
value is greater than or equal to the absolute value of sem_op. Then
the absolute value of sem_op is subtracted from the semaphore's
current value.
The sem_flg value specifies whether or not the thread is willing to
wait, and also whether or not the thread wants the system to keep a semaphore
adjustment value for the semaphore.
Semaphore waits are visible from the Work with Active Jobs display. A thread
waiting on a semaphore in a semaphore set appears to be in a semaphore wait
state (SEMW) on the Work with Threads display (requested using the WRKJOB
command and taking option 20). Displaying the call stack of the thread shows
the semop() function near the bottom of the stack.
A thread removes a semaphore set ID by calling the semctl()
function. The thread also can use the semctl() function to
change the data structure values associated with the semaphore set ID or to
retrieve the data structure values associated with the semaphore set ID. The
following parameters are passed in:
- Semaphore set ID
- Command the thread wants to perform (remove ID, set data structure values,
receive data structure values),
- Pointer to a buffer from which to set data structure values, or in which to
receive data structure values.
In addition, the semctl() function can perform various
other control operations on a specific semaphore within a set, or on an entire
semaphore set:
- Set or retrieve a semaphore value.
- Retrieve the process ID of the last thread to operate on a semaphore.
- Retrieve the number of threads waiting for a semaphore value to
increase.
- Retrieve the number of threads waiting for a semaphore value to become
zero.
- Retrieve the value of every semaphore in a semaphore set.
- Set the value of every semaphore in a semaphore set.
Semaphore Set Differences and Restrictions
i5/OS semaphore sets differ from the definition in the Single
UNIX Specification in the following ways:
- The Single UNIX Specification does not define threads. Consequently,
Single UNIX Specification semaphores are defined in terms of processes and the semaphore:
- Causes the entire process to wait
- Releases resources when the process ends
i5/OS handles semaphores at the thread level. An i5/OS semaphore:
- Causes only a single thread to wait
- Releases resources when the thread ends
- The maximum number of semaphore sets that can be created (system-wide) is
2 147 483 646.
- The maximum number of semaphores per semaphore set is 65535.
- Semaphores values are limited to the range from 0 to 65535. Adjustment
values associated with a semaphore are limited to the range -32767 to
32767.
The semaphore set functions are:
- semctl() (Perform Semaphore Control Operations) provides semaphore control operations as specified by cmd on the semaphore specified by semnum in the semaphore set specified by semid.
- semget() (Get Semaphore Set with Key) returns the semaphore ID associated with the specified semaphore key.
- semop() (Perform Semaphore Operations on Semaphore Set) performs operations on semaphores in a semaphore set. These operations are supplied in a user-defined array of operations.
See also IPC Key Generation Functions for additional semaphore set functions.