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