Linux inter-process communication (System V) --- semaphore
Semaphore IPC Principle
Semaphore communication mechanism is mainly used to synchronize processes to avoid concurrent access to shared resources. Semaphores can identify the number of available system resources. The simplest semaphores are binary semaphores.
This is a conceptual diagram of the Linux semaphore communication mechanism. In practice, two processes may use multiple semaphores for communication. Therefore, Linux manages semaphores in terms of semaphores.
Generally, creating a semaphore actually creates a set of semaphores. In this collection, there may be multiple semaphores. The entire semaphore collection consists of the following parts.
1. semaphore collection Data Structure: This Data Structure defines the basic attributes of the entire semaphore collection, such as access permissions. 2. semaphore: the semaphore set uses a pointer to point to a semaphore unit consisting of an array, where the values of each semaphore are stored.
The data structure of the semaphore set is defined as follows:
From/usr/include/linux/sem. hstruct semid_ds {struct ipc_perm sem_perm;/* permissions .. see ipc. h permission */_ kernel_time_t sem_otime;/* last semop time */_ kernel_time_t sem_ctime;/* last change time last modification time */struct sem * sem_base; /* ptr to first semaphore in array first semaphore */struct sem_queue * sem_pending;/* pending operations to be processed blocked semaphore */struct sem_queue ** sem_pending_last; /* last pending operation the last blocked semaphore */struct sem_undo * undo;/* undo requests on this array undo queue */unsigned short sem_nsems;/* no. of semaphores in array semaphores */};
The data structure of semaphores is defined as follows:
From/usr/src/kernels/xxx/include/linux/sem. hxxx is the uname-r command, and the obtained struct sem {int semval;/* current value semaphore value */int sempid; /* pid of the process ID of the last operation */};
Linux semaphore management operations
1. Create a semaphore set
# Include <sys/types. h> # include <sys/ipc. h> # include <sys/sem. h>/** the first parameter is the key value. Generally, the ftok () function generates * The second parameter is the number of semaphores created, store as an array * The third parameter is used to identify the permissions of the semaphore Set */int semget (key_t key, int nsems, int semflg );
2. Control semaphores set and semaphores
# Include <sys/types. h> # include <sys/ipc. h> # include <sys/sem. h>/** the first parameter is the semaphore identifier to be operated * The second parameter. If you want to operate a semaphore, It is the subscript of the semaphore. If you want to operate a set, this parameter is meaningless * The third parameter is the operation to be executed * The fourth parameter needs to be set according to the third parameter, its type is senum's shared body */int semctl (int semid, int semnum, int cmd ,...); semun shares the following: union semun {int val;/* Value for SETVAL */struct semid_ds * buf;/* Buffer for IPC_STAT, IPC_SET */unsigned short * array; /* Array for GETALL, SETALL */struct seminfo * _ buf;/* Buffer for IPC_INFO (Linux-specific )*/};
3. semaphore operations
# Include <sys/types. h> # include <sys/ipc. h> # include <sys/sem. h>/** the first parameter is the identifier of the semaphore to be operated * The second parameter is the sembuf struct * The third parameter is the number of sops */int semop (int semid, struct sembuf * sops, unsigned nsops); sembuf struct: struct sembuf {unsigned short sem_num;/* semaphore index in array semaphore subscript */short sem_op; /* semaphore operation */short sem_flg;/* operation flags operation identifier */}; sem_flg indicates the operation identifier. Optional values: IPC_NOWAIT: if the operation on the semaphore set cannot be performed, the call returns immediately. SEM_UNDO: after a process exits, the operations performed by the process on the sem will be revoked.
Program instance
The following uses a program to demonstrate the effect of SEM_UNDO:
# Include <stdio. h> # include <sys/types. h> # include <sys/ipc. h> # include <sys/sem. h> # include <unistd. h> # include <stdlib. h> union semun {int val;/* Value for SETVAL */struct semid_ds * buf;/* Buffer for IPC_STAT, IPC_SET */unsigned short * array;/* Array for GETALL, SETALL */struct seminfo * _ buf;/* Buffer for IPC_INFO */}; static void sem_init (int id) {union semun sem; sem. val = 10;/* initialize the semaphore value */ Semctl (id, 0, SETVAL, sem);} static void sem_v (int id) {struct sembuf buf = {. sem_num = 0 ,. sem_op =-1,/* can be changed to SEM_UNDO to view the result *///. sem_flg = 0 ,. sem_flg = SEM_UNDO,};/* operation semaphore */semop (id, & buf, 1);} static int get_val (int id) {/* obtain the semaphore value */return semctl (id, 0, GETVAL);} int main () {int sem_id, pid; /* Create a semaphore Set */sem_id = semget (key_t) 1004, 1, IPC_CREAT | 0600); sem_init (sem_id); if (pid = K () =-1) {perror ("fork Err"); exit (0);} else if (! Pid) {sem_v (sem_id); printf ("child: % d \ n", get_val (sem_id);} else {sleep (1); printf ("parent: % d \ n ", get_val (sem_id);} return 0 ;}
If the SEM_UNDO flag is not used, the sub-process outputs 9 and the parent process outputs 9;
If the SEM_UNDO ID is used, the sub-process outputs 9 and the parent process outputs 10.