当操作信号量(semop)时,sem_flg可以设置SEM_UNDO标识;SEM_UNDO用于将修改的信号量值在进程正常退出(调用exit退出或main执行完)或异常退出(如段异常、除0异常、收到KILL信号等)时归还给信号量。
如信号量初始值是20,进程以SEM_UNDO方式操作信号量减2,减5,加1;在进程未退出时,信号量变成20-2-5+1=14;在进程退出时,将修改的值归还给信号量,信号量变成14+2+5-1=20。
I.SEM_UNDO示例
i.建立包含两个信号量的信号量集,第一个信号量置20,第二个信号量置10
- [redhat@localhost sem]$ ipcmk -S 2
- Semaphore id: 131075
- [redhat@localhost sem]$ ./seminfo
- command : ./seminfo semid
- [redhat@localhost sem]$ ./seminfo 131075
- key:585c7c37
- semid:131075
- nsems:2
- -------sem details---------
- semnum:0, semval:0
- semnum:1, semval:0
- [redhat@localhost sem]$ ./semop
- command : ./semop semid semnum semops undo[0|1] sleeps[0-15]
- [redhat@localhost sem]$ ./semop 131075 0 20 0 0
- [redhat@localhost sem]$ ./semop 131075 1 10 0 0
- [redhat@localhost sem]$ ./seminfo 131075
- key:585c7c37
- semid:131075
- nsems:2
- -------sem details---------
- semnum:0, semval:20
- semnum:1, semval:10
ii.不设置SEM_UNDO,将第一个信号量减2;进程未退出时,信号量由20变成18;进程正常退出时,保持18不变。
设置SEM_UNDO,将第二个信号量减2;进程未退出时,信号量由10变成8;进程正常退出时,将2归还给信号量,信号量重新变回10
- [redhat@localhost sem]$ ./semop 131075 0 -2 0 0
- [redhat@localhost sem]$ ./semop 131075 1 -2 1 15 &
- [1] 3339
- [redhat@localhost sem]$ ./seminfo 131075
- key:585c7c37
- semid:131075
- nsems:2
- -------sem details---------
- semnum:0, semval:18
- semnum:1, semval:8
- [redhat@localhost sem]$ ./seminfo 131075
- key:585c7c37
- semid:131075
- nsems:2
- -------sem details---------
- semnum:0, semval:18
- semnum:1, semval:8
- [redhat@localhost sem]$ ./seminfo 131075
- key:585c7c37
- semid:131075
- nsems:2
- -------sem details---------
- semnum:0, semval:18
- semnum:1, semval:10
- [1]+ Done ./semop 131075 1 -2 1 15
iii.不设置SEM_UNDO,将第一个信号量减2;进程未退出时,信号量由18变成16;进程非正常退出时,保持16不变。
设置SEM_UNDO,将第二个信号量减2;进程未退出时,信号量由10变成8;进程非正常退出时,将2归还给信号量,信号量重新变回10
- [redhat@localhost sem]$ ./semop 131075 0 -2 0 10 & ./semop 131075 1 -2 1 15&
- [1] 3352
- [2] 3353
- [redhat@localhost sem]$ ./seminfo 131075
- key:585c7c37
- semid:131075
- nsems:2
- -------sem details---------
- semnum:0, semval:16
- semnum:1, semval:8
- [redhat@localhost sem]$ kill -9 3073
- [redhat@localhost sem]$ kill -9 3074
- [redhat@localhost sem]$ ./seminfo 131075
- key:585c7c37
- semid:131075
- nsems:2
- -------sem details---------
- semnum:0, semval:16
- semnum:1, semval:10
- [2]+ 已杀死 ./semop 131075 1 -2 1 15
附:
seminfo与semop代码如下:
查看信号量信息:seminfo.c
- 1 #include <stdio.h>
- 2 #include <sys/sem.h>
- 3 #include <stdlib.h>
- 4 #include <errno.h>
- 5
- 6 #define SEMMSL 250
- 7 #define BUFSIZE 50
- 8
- 9 #define error() \
- 10 do { \
- 11 char buf[BUFSIZE]; \
- 12 snprintf(buf, BUFSIZE, "[%s][%d][%d]\n", __FILE__, __LINE__, errno); \
- 13 perror(buf); \
- 14 } while(0);
- 15
- 16 void help(char *prgm)
- 17 {
- 18 printf("command : %s semid\n", prgm);
- 19 }
- 20
- 21 int seminfo(int semid)
- 22 {
- 23 struct semid_ds semds;
- 24 short semval[SEMMSL];
- 25 int err;
- 26
- 27 err = semctl(semid, 0, IPC_STAT, &semds);
- 28 if (err == -1) {
- 29 error();
- 30 return err;
- 31 }
- 32
- 33 printf("key:%x\n", semds.sem_perm.__key);
- 34 printf("semid:%d\n", semid);
- 35 printf("nsems:%d\n", semds.sem_nsems);
- 36
- 37 if (semds.sem_nsems > SEMMSL) {
- 38 printf("SEMMSL small!!\n");
- 39 return -1;
- 40 }
- 41
- 42 err = semctl(semid, 0 ,GETALL, semval);
- 43 if (err == -1) {
- 44 error();
- 45 return err;
- 46 }
- 47
- 48 printf("-------sem details---------\n");
- 49 int i=0;
- 50 for(; i < semds.sem_nsems; i++) {
- 51 printf("semnum:%d, semval:%d\n", i, semval[i]);
- 52 }
- 53
- 54 return 0;
- 55 }
- 56
- 57 int main(int argc, char *argv[])
- 58 {
- 59 int semid;
- 60 int err;
- 61
- 62 if (argc != 2) {
- 63 help(argv[0]);
- 64 return -1;
- 65
- 66 semid = atoi(argv[1]);
- 67
- 68 err = seminfo(semid);
- 69 if (err) {
- 70 exit(-1);
- 71 }
- 72
- 73 return 0;
- 74
- 75 }
信号量操作:semop.c
- 1 #include <stdio.h>
- 2 #include <sys/sem.h>
- 3 #include <stdlib.h>
- 4 #include <errno.h>
- 5 #include <unistd.h>
- 6
- 7 #define SEMMSL 250
- 8 #define BUFSIZE 50
- 9
- 10 #define error() \
- 11 do { \
- 12 char buf[BUFSIZE]; \
- 13 snprintf(buf, BUFSIZE, "[%s][%d][%d]\n", __FILE__, __LINE__, errno); \
- 14 perror(buf); \
- 15 } while(0);
- 16
- 17 void help(char *prgm)
- 18 {
- 19 printf("command : %s semid semnum semops undo[0|1] sleeps[0-15]\n", prgm);
- 20 }
- 21
- 22 int main(int argc, char *argv[])
- 23 {
- 24 int semid, semnum, semops, undo, sleeps;
- 25 int err;
- 26 struct sembuf sembuf;
- 27
- 28 if (argc != 6) {
- 29 help(argv[0]);
- 30 return -1;
- 31 }
- 32
- 31 }
- 32
- 33 semid = atoi(argv[1]);
- 34 semnum = atoi(argv[2]);
- 35 semops = atoi(argv[3]);
- 36 undo = atoi(argv[4]);
- 37 sleeps = atoi(argv[5]);
- 38
- 39 if (undo != 0 && undo != 1) {
- 40 printf("invalid undo\n");
- 41 return -1;
- 42 }
- 43
- 44 if (sleeps < 0 || sleeps > 15) {
- 45 printf("invalid sleeps\n");
- 46 return -1;
- 47 }
- 48
- 49 sembuf.sem_num = semnum;
- 50 sembuf.sem_op = semops;
- 51 sembuf.sem_flg = undo ? SEM_UNDO : 0;
- 52 err = semop(semid, &sembuf, 1);
- 53 if (err) {
- 54 error();
- 55 return -1;
- 56 }
- 57
- 58 sleep(sleeps);
- 59
- 60 return 0;
- 61
- 62 }