Linux inter-process communication (IPC) Programming Practice (9) System V semaphores-A toolset for encapsulating a semaphores operation
Main API # include # Include
# Include Int semget (key_t key, int nsems, int semflg );
Int semctl (int semid, int semnum, int cmd,...); int semop (int semid, struct sembuf * sops, unsigned nsops );
Semget
Int semget (key_t key, int nsems, int semflg);/** Example 1: encapsulate a function to create a semaphore set. The semaphore set contains one semaphore;
The permission is 0666.
**/int sem_create(key_t key){int semid = semget(key, 1, IPC_CREAT|IPC_EXCL|0666);if (semid == -1)err_exit("sem_create error");return semid;}
/** Example 2: open a semaphore set nsems (number of semaphores) and enter 0,
Semflg (semaphore permission) can also be set to 0, indicating that the default permission is enabled.
**/int sem_open(key_t key){int semid = semget(key, 0, 0);if (semid == -1)err_exit("sem_open error");return semid;}int semctl(int semid, int semnum, int cmd, ...);
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)*/};
// Struct semid_ds: The data structure maintained by the Linux kernel for the System V semaphore struct semid_ds {struct ipc_perm sem_perm;/* Ownership and permissions */time_t sem_otime; /* Last semop time */time_t sem_ctime;/* Last change time */unsigned long sem_nsems;/* No. of semaphores in set */};
/** Example 1: set the value of the first semaphore in the semid of the semaphore set to value (SETVAL). Note: The semun consortium must be provided by itself (copy it from man-page)
**/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) */};int sem_setval(int semid, int value){union semun su;su.val = value;if (semctl(semid, 0, SETVAL, su) == -1)err_exit("sem_setval error");return 0;}
/** Example 2: Get the value (GETVAL) associated with the first signal in the semaphore set)
Note: the fourth parameter can be left blank, and the value associated with the semaphore can be returned through the return value of semctl (the value of semval .)
**/int sem_getval(int semid){int value = semctl(semid, 0, GETVAL);if (value == -1)err_exit("sem_getval error");return value;return 0;}
/** Example 3: delete a semaphore set (Delete the entire set)
IPC_RMID Immediately remove (delete now) the semaphore set, awakening all processes blocked in semop (2) callon the set (with an error return and errno set to EIDRM) [Then wake up all processes blocked on the semaphore]. the argument semnum is ignored [ignore The second parameter]. **/int sem_delete (int semid) {if (semctl (semid, 0, IPC_RMID) =-1) err_exit ("sem_delete error"); return 0 ;} // test code int main (int argc, char * argv []) {int semid = sem_create (0x1234); // create a semaphore set sem_setval (semid, 500 ); // set the cout value <sem_getval (semid) <endl; // obtain the value sleep (10); sem_delete (semid); // Delete the set }/**
Example 4: Obtain/set the semaphore permission
Note: You must set the struct semid_ds struct to specify which field of semun to use.
**/Int sem_getmode (int semid) {union semun su; // Note: The following two statements must be set. // (tell the kernel which field of semun is used) struct semid_ds sd; su. buf = & sd; // if (semctl (semid, 0, IPC_STAT, su) =-1) err_exit ("sem_getmode error"); printf ("current permissions is: % o \ n ", su. buf-> sem_perm.mode); return 0;} int sem_setmode (int semid, char * mode) {union semun su; // Note: The following two statements must be set. // (tell the kernel which field of semun is used) struct semid_ds sd; su. buf = & sd; // sscanf (mode, "% o", (unsigned int *) & su. buf-> sem_perm.mode); if (semctl (semid, 0, IPC_SET, su) =-1) err_exit ("sem_setmode error"); return 0 ;} [cpp] view plaincopy: view the CODE piece on the CODE and derive it to my CODE piece int semop (int semid, struct sembuf * sops, unsigned nsops ); [cpp] view plaincopy view CODE piece derived from my CODE piece on CODE // The sembuf struct sembuf {unsigned short sem_num;/* semaphore number: semaphore number (starting from 0) */short sem_op;/* semaphore operation (+ 1, 0,-1) */short sem_flg;/* operation flags: the common value is SEM_UNDO (see the following description )*/};
/** Example: P, V Operation encapsulation ** you can set the third parameter of sembuf to IPC_NOWAIT/0, to view changes in the program status **/int sem_P (int semid) {struct sembuf sops = {0,-1, SEM_UNDO}; if (semop (semid, & sops, 1) =-1) err_exit ("sem_P error"); return 0;} int sem_V (int semid) {struct sembuf sops = {0, + 1, SEM_UNDO }; if (semop (semid, & sops, 1) =-1) err_exit ("sem_V error"); return 0 ;}
Below we encapsulate a semaphores Operation Function Tool to encapsulate the main operations, which can be used like a command.
/** Example of semaphores: After compilation, run the./semtool directly. The program will print the usage of the tool;
The following function calls are just a slight change to the encapsulated function above, which is not difficult to understand;
**///semtool.cpp#include "Usage.h"int main(int argc,char *argv[]){int opt = getopt(argc, argv, "cdpvs:gfm:");if (opt == '?')exit(EXIT_FAILURE);else if (opt == -1){usage();exit(EXIT_FAILURE);}key_t key = ftok(".", 's');int semid;switch (opt){case 'c':sem_create(key);break;case 'd':semid = sem_open(key);sem_delete(semid);break;case 'p':semid = sem_open(key);sem_P(semid);sem_getval(semid);break;case 'v':semid = sem_open(key);sem_V(semid);sem_getval(semid);break;case 's':semid = sem_open(key);sem_setval(semid, atoi(optarg));sem_getval(semid);break;case 'g':semid = sem_open(key);sem_getval(semid);break;case 'f':semid = sem_open(key);sem_getmode(semid);break;case 'm':semid = sem_open(key);sem_setmode(semid, argv[2]);sem_getmode(semid);break;default:break;}return 0;}
// Usage. h # ifndef USAGE_H_INCLUDED # define USAGE_H_INCLUDED # include # include # includeusing namespace std; inline void err_quit (std: string message); inline void err_exit (std: string message); void usage () {cerr <"Usage:" <endl; cerr <". /semtool-c # create "<endl; cerr <". /semtool-d # delte "<endl; cerr <". /semtool-p # signal "<endl; cerr <". /semtool-v # wait "<endl; cerr <". /semtool-s # set-value "<endl; cerr <". /semtool-g # get-value "<endl; cerr <". /semtool-f # print-mode "<endl; cerr <". /semtool-m # set-mode "<endl;} int sem_create (key_t key) {int semid = semget (key, 1, IPC_CREAT | IPC_EXCL | 0666 ); if (semid =-1) err_exit ("sem_create error"); return semid;} int sem_open (key_t key) {int semid = semget (key, 0, 0 ); if (semid =-1) err_exit ("sem_open error"); return semid;} 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) */}; int sem_getmode (int semid) {union semun su; // Note: The following two statements must be set. // (tell the kernel which field of semun is used) struct semid_ds sd; su. buf = & sd; // if (semctl (semid, 0, IPC_STAT, su) =-1) err_exit ("sem_getmode error"); printf ("current permissions is: % o \ n ", su. buf-> sem_perm.mode); return 0;} int sem_setmode (int semid, char * mode) {union semun su; // Note: The following two statements must be set. // (tell the kernel which field of semun is used) struct semid_ds sd; su. buf = & sd; // sscanf (mode, "% o", (unsigned int *) & su. buf-> sem_perm.mode); if (semctl (semid, 0, IPC_SET, su) =-1) err_exit ("sem_setmode error"); return 0 ;} int sem_getval (int semid) {int value = semctl (semid, 0, GETVAL); if (value =-1) err_exit ("sem_getval error "); cout <"current value:" <value <endl; return value;} int sem_setval (int semid, int value) {union semun su; su. val = value; if (semctl (semid, 0, SETVAL, su) =-1) err_exit ("sem_setval error"); return 0;} int sem_delete (int semid) {if (semctl (semid, 0, IPC_RMID) =-1) err_exit ("sem_delete error"); return 0 ;}// to print the constant variation of the semaphore, therefore, sem_flg does not use SEM_UNDO // but we recommend that you use SEM_UNDOint sem_P (int semid) {struct sembuf sops = {0,-1, 0}; if (semop (semid, & sops, 1) =-1) err_exit ("sem_P error"); return 0;} int sem_V (int semid) {struct sembuf sops = {0, + 1, 0}; if (semop (semid, & sops, 1) =-1) err_exit ("sem_V error"); return 0;} inline void err_quit (std :: string message) {std: cerr <message <std: endl; exit (EXIT_FAILURE);} inline void err_exit (std: string message) {perror (message. c_str (); exit (EXIT_FAILURE) ;}# endif // USAGE_H_INCLUDED
Appendix: ftok Function
An ID value must be specified for the system to establish IPC communication (such as message queue and shared memory. Generally, this id value is obtained through the ftok function.
The ftok prototype is as follows:
key_t ftok( char * fname, int id )
Fname indicates the name of the file you specified (the file must exist and be accessible), and id indicates the sub-serial number, although it is an int, however, only 8 bits are used (0-255 ).
Return Value:
When the execution is successful, a key_t value will be returned, otherwise-1 will be returned.
After obtaining the key, we can use this key as the key value for inter-process communication in a certain method.