14.5 POSIX:SEM Named Semaphores

Team-FLY

POSIX:SEM named semaphores can synchronize processes that do not share memory. Named semaphores have a name, a user ID, a group ID and permissions just as files do. A semaphore name is a character string that conforms to the construction rules for a pathname. POSIX does not require that the name appear in the filesystem, nor does POSIX specify the consequences of having two processes refer to the same name unless the name begins with the slash character. If the name begins with a slash ( / ), then two processes (or threads) that open the semaphore with that name refer to the same semaphore. Consequently, always use names beginning with a / for POSIX:SEM named semaphores. Some operating systems impose other restrictions on semaphore names.

14.5.1 Creating and opening named semaphores

The sem_open function establishes the connection between a named semaphore and a sem_t value. The name parameter is a string that identifies the semaphore by name. This name may or may not correspond to an actual object in the file system. The oflag parameter determines whether the semaphore is created or just accessed by the function. If the O_CREAT bit of oflag is set, the sem_open requires two more parameters: a mode parameter of type mode_t giving the permissions and a value parameter of type unsigned giving the initial value of the semaphore. If both the O_CREAT and O_EXCL bits of oflag are set, the sem_open returns an error if the semaphore already exists. If the semaphore already exists and O_CREAT is set but O_EXCL is not set, the semaphore ignores O_CREAT and the additional parameters. POSIX:SEM does not provide a way to directly set the value of a named semaphore once it already exists.

  SYNOPSIS  #include <semaphore.h>   sem_t *sem_open(const char *name, int oflag, ...);  POSIX:SEM  

If successful, the sem_open function returns the address of the semaphore. If unsuccessful , sem_open returns SEM_FAILED and sets errno . The following table lists the mandatory errors for sem_open .

errno

cause

EACCES

permissions incorrect

EEXIST

O_CREAT and O_EXCL are set and semaphore exists

EINTR

sem_open was interrupted by a signal

EINVAL

name can't be opened as a semaphore, or tried to create semaphore with value greater than SEM_VALUE_MAX

EMFILE

too many file descriptors or semaphores in use by process

ENAMETOOLONG

name is longer than PATH_MAX , or it has a component that exceeds NAME_MAX

ENFILE

too many semaphores open on the system

ENOENT

O_CREAT is not set and the semaphore doesn't exist

ENOSPC

not enough space to create the semaphore

Program 14.7 shows a getnamed function that creates a named semaphore if it doesn't already exist. The getnamed function can be called as an initialization function by multiple processes. The function first tries to create a new named semaphore. If the semaphore already exists, the function then tries to open it without the O_CREAT and O_EXCL bits of the oflag parameter set. If successful, getnamed returns 0. If unsuccessful, getnamed returns “1 and sets errno .

Program 14.7 getnamed.c

A function to access a named semaphore, creating it if it doesn't already exist .

 #include <errno.h> #include <fcntl.h> #include <semaphore.h> #include <sys/stat.h> #define PERMS (mode_t)(S_IRUSR  S_IWUSR  S_IRGRP  S_IROTH) #define FLAGS (O_CREAT  O_EXCL) int getnamed(char *name, sem_t **sem, int val) {     while (((*sem = sem_open(name, FLAGS, PERMS, val)) == SEM_FAILED) &&             (errno == EINTR)) ;     if (*sem != SEM_FAILED)         return 0;     if (errno != EEXIST)         return -1;     while (((*sem = sem_open(name, 0)) == SEM_FAILED) && (errno == EINTR)) ;     if (*sem != SEM_FAILED)         return 0;     return -1; } 

The first parameter of getnamed is the name of the semaphore and the last parameter is the value to use for initialization if the semaphore does not already exist. The second parameter is a pointer to a pointer to a semaphore. This double indirection is necessary because getnamed needs to change a pointer. Note that if the semaphore already exists, getnamed does not initialize the semaphore.

Program 14.8 shows a modification of Program 14.1 that uses named semaphores to protect the critical section. Program 14.8 takes three command-line arguments: the number of processes, the delay and the name of the semaphore to use. Each process calls the getnamed function of Program 14.7 to gain access to the semaphore. At most, one of these will create the semaphore. The others will gain access to it.

Exercise 14.20

What happens if two copies of chainnamed , using the same named semaphore run simultaneously on the same machine?

Answer:

With the named semaphores, each line will be printed without interleaving.

Exercise 14.21

What happens if you enter Ctrl-C while chainnamed is running and then try to run it again with the same named semaphore?

Answer:

Most likely the signal generated by Ctrl-C will be delivered while the semaphore has value 0. The next time the program is run, all processes will block and no output will result.

14.5.2 Closing and unlinking named semaphores

Like named pipes or FIFOs (Section 6.3), POSIX:SEM named semaphores have permanence beyond the execution of a single program. Individual programs can close named semaphores with the sem_close function, but doing so does not cause the semaphore to be removed from the system. The sem_close takes a single parameter, sem , specifying the semaphore to be closed.

  SYNOPSIS  #include <semaphore.h>   int sem_close(sem_t *sem);  POSIX:SEM  

If successful, sem_close returns 0. If unsuccessful, sem_close returns “1 and sets errno . The sem_close function sets errno to EINVAL if *sem is not a valid semaphore.

Program 14.8 chainnamed.c

A process chain with a critical section protected by a POSIX:SEM named semaphore .

 #include <errno.h> #include <semaphore.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> #include "restart.h" #define BUFSIZE 1024 int getnamed(char *name, sem_t **sem, int val); int main  (int argc, char *argv[]) {     char buffer[BUFSIZE];     char *c;     pid_t childpid = 0;     int delay;     volatile int dummy = 0;     int i, n;     sem_t *semlockp;     if (argc != 4){       /* check for valid number of command-line arguments */         fprintf (stderr, "Usage: %s processes delay semaphorename\n", argv[0]);         return 1;     }     n = atoi(argv[1]);     delay = atoi(argv[2]);     for (i = 1; i < n; i++)         if (childpid = fork())             break;     snprintf(buffer, BUFSIZE,              "i:%d  process ID:%ld  parent ID:%ld  child ID:%ld\n",              i, (long)getpid(), (long)getppid(), (long)childpid);     c = buffer;     if (getnamed(argv[3], &semlockp, 1) == -1) {         perror("Failed to create named semaphore");         return 1;     }     while (sem_wait(semlockp) == -1)                         /* entry section */         if (errno != EINTR) {             perror("Failed to lock semlock");             return 1;         }     while (*c != ' 
 #include <errno.h> #include <semaphore.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> #include "restart.h" #define BUFSIZE 1024 int getnamed(char *name, sem_t **sem, int val); int main (int argc, char *argv[]) { char buffer[BUFSIZE]; char *c; pid_t childpid = 0; int delay; volatile int dummy = 0; int i, n; sem_t *semlockp; if (argc != 4){ /* check for valid number of command-line arguments */ fprintf (stderr, "Usage: %s processes delay semaphorename\n", argv[0]); return 1; } n = atoi(argv[1]); delay = atoi(argv[2]); for (i = 1; i < n; i++) if (childpid = fork()) break; snprintf (buffer, BUFSIZE, "i:%d process ID:%ld parent ID:%ld child ID:%ld\n", i, (long)getpid(), (long)getppid(), (long)childpid); c = buffer; if (getnamed(argv[3], &semlockp, 1) == -1) { perror("Failed to create named semaphore"); return 1; } while (sem_wait(semlockp) == -1) /* entry section */ if (errno != EINTR) { perror("Failed to lock semlock"); return 1; } while (*c != '\0') { /* critical section */ fputc (*c, stderr); c++; for (i = 0; i < delay; i++) dummy++; } if (sem_post(semlockp) == -1) { /* exit section */ perror("Failed to unlock semlock"); return 1; } if (r_wait(NULL) == -1) /* remainder section */ return 1; return 0; } 
') { /* critical section */ fputc(*c, stderr); c++; for (i = 0; i < delay; i++) dummy++; } if (sem_post(semlockp) == -1) { /* exit section */ perror("Failed to unlock semlock"); return 1; } if (r_wait(NULL) == -1) /* remainder section */ return 1; return 0; }

The sem_unlink function, which is analogous to the unlink function for files or FIFOs, performs the removal of the named semaphore from the system after all processes have closed the named semaphore. A close operation occurs when the process explicitly calls sem_close, _exit, exit , exec or executes a return from main . The sem_unlink function has a single parameter, a pointer to the semaphore that is to be unlinked .

  SYNOPSIS  #include <semaphore.h>   int sem_unlink(const char *name);  POSIX:SEM  

If successful, sem_unlink returns 0. If unsuccessful, sem_unlink returns “1 and sets errno . The following table lists the mandatory errors for sem_unlink .

errno

cause

EACCES

permissions incorrect

ENAMETOOLONG

name is longer than PATH_MAX , or it has a component that exceeds NAME_MAX

ENOENT

the semaphore doesn't exist

Calls to sem_open with the same name refer to a new semaphore after a sem_unlink , even if other processes still have the old semaphore open. The sem_unlink function always returns immediately, even if other processes have the semaphore open.

Exercise 14.22

What happens if you call sem_close for an unnamed semaphore that was initialized by sem_init rather than sem_open?

Answer:

The POSIX standard states that the result of doing this is not defined.

Program 14.9 shows a function that closes and unlinks a named semaphore. The destroynamed calls the sem_unlink function, even if the sem_close function fails. If successful, destroynamed returns 0. If unsuccessful, destroynamed returns “1 and sets errno .

Remember that POSIX:SEM named semaphores are persistent. If you create one of these semaphores, it stays in the system and retains its value until destroyed, even after the process that created it and all processes that have access to it have terminated . POSIX:SEM does not provide a method for determining which named semaphores exist. They may or may not show up when you display the contents of a directory. They may or may not be destroyed when the system reboots.

Program 14.9 destroynamed.c

A function that closes and unlinks a named semaphore .

 #include <errno.h> #include <semaphore.h> int destroynamed(char *name, sem_t *sem) {     int error = 0;     if (sem_close(sem) == -1)         error = errno;     if ((sem_unlink(name) != -1) && !error)         return 0;     if (error)        /* set errno to first error that occurred */         errno = error;     return -1; } 
Team-FLY


Unix Systems Programming
UNIX Systems Programming: Communication, Concurrency and Threads
ISBN: 0130424110
EAN: 2147483647
Year: 2003
Pages: 274

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net