当操作信号量(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 }