Using System V Semaphores

The System V interface for using semaphores is anything but intuitive because the concept of a semaphore has been expanded well beyond its actual definition. Semaphores are no longer treated as simple variables to support atomic execution of predefined operations. Instead, a System V semaphore now refers to a whole set of semaphores, which allows not just one but several operations to be performed at the same time (although they appear to be atomic to users). It is, of course, possible to request a semaphore set with just a single semaphore and to define functions that simulate the behavior of simple operations. The following sample program shows how semaphores are used:

#include<stdio.h> #include<sys/types.h> #include<sys/ipc.h> #include<sys/sem.h>

#define SEMKEY 1234L /* Identifier */

#define PERMS 0666 /* Access permission: rwrwrw */

struct sembuf op_down[1] = { 0, -1 , 0 }; struct sembuf op_up[1] = { 0, 1 , 0 };

int res; /* Result of semaphore operations */

/* Test whether semaphore already exists */ semid = semget(SEMKEY, 0, IPC_CREAT | PERMS); if (semid < 0) {

printf("Create the semaphore\n");

semid = semget(SEMKEY, 1, IPC_CREAT | PERMS); if (semid < 0) {

printf("Couldn't create semaphore!\n"); exit(-1);

/* Perform down operation */

printf("Before critical code\n"); down();

/* Critical code */ printf("In critical code\n"); sleep(10); up();

A new semaphore with a permanently defined magic number (1234) is first created in main for purposes of identification within the system. Because several copies of the program are to run in parallel, it is necessary to test whether a corresponding semaphore already exists. If not, one is created. This is done using the semget system call to reserve a semaphore set. It requires the following parameters: the magic number (semkey), the number of semaphores in the set (1), and the desired access permissions. The above sample program creates a semaphore set with just a single semaphore. The access permissions indicate that all users have both read and write access to the semaphore.8 Then the value of the single semaphore in the semaphore set is initialized to 1 using the semctl system call. The semid variable identifies the semaphore in the kernel (it can be obtained with the help of the magic number of any other program).

8IPC_CREAT is a system constant that must be ''ORed''with the access number to specify that a new semaphore is to be created.

0 specifies that we want to manipulate the semaphore with identifier 0 in our semaphore set (this is the only semaphore in our set). The meaning of setval, 1 is obvious — the semaphore value is to be set to 1.9

The familiar up and down operations are implemented by procedures of the same name. How the semaphore value is modified in the SysV scheme is interesting. Operations are performed using the semop system call, and, as usual, the semid variable is used to identify the desired semaphore. Of particular note are the last two arguments. One is a pointer to an array with sembuf elements, each of which represents a semaphore operation. The number of operations in the array is defined by an integer argument because the kernel cannot otherwise identify the operations.

Entries in the sembuf array consist of three elements with the following meanings:

1. The first entry serves to select the semaphore in the semaphore set.

2. The second entry specifies the desired operation. 0 waits until the value of the semaphore reaches 0; a positive number is added to the value of the semaphore (and corresponds to releasing a resource; the process cannot go to sleep with this action); a negative number is used to request resources. If the absolute value is less than the value of the semaphore, its (absolute) value is subtracted from the current semaphore value without sleeping on the semaphore; otherwise, the process blocks until the semaphore value reaches a value that allows the operation to be performed.

3. The third entry is a flag used for fine control of the operation.

The behavior of a semaphore can be simulated by using 1 and -1 as numeric arguments. down tries to subtract 1 from the semaphore counter (and goes to sleep when the semaphore value reaches 0), while up adds 1 to the semaphore value and therefore corresponds to releasing a resource.

The code yields the following result:

[email protected]> ,/sema Create the semaphore Before the critical code In the critical code

The program creates the semaphore, enters the critical code, and waits there for 10 seconds. Before the code is entered, a down operation is performed to decrement the semaphore value to 0. A second process started during the wait period is not allowed to enter critical code.

[email protected]> ,/sema Before the critical code

Any attempt to enter critical code triggers a down operation, which tries to subtract 1 from the semaphore value. This fails because the current value is 0. The process goes to sleep on the semaphore. It is not woken until the first process has released the resource by means of an up operation (and the semaphore value has reverted to 1). It can then decrement the semaphore value and enter the critical code.

Continue reading here: Data Structures

Was this article helpful?

0 0