原理不多讲,可能查看unix 高级环境编程,只提一些注意点
信号量系统限制
- 信号量最大值 32767
- 最多信号量集 128
- 每个集中最多含有250信号量
难理解的是标志位SEM_UNDO
以下是个人愚见:
首先是了解一下"信号量调整值",每一个信号量都会对应有一个调整值,并且对信号量进行操作的时候进行维护。如果设置了SEM_UNDO则立即更新,如果没有何时更新,我也不知道,可能是系统调度吧;
在进行退出,无论是正常还是异常,内核都会遍历一次进程的调整值,进行处理,具体怎样处理有待研究;
个人经验:如果在V 和 P 操作上, 如果需要阻塞的,最好标志位上赋SEM_UNDO,如果不阻塞那就不需要,这样会少点意想不到的错误
网上解释:
每一个独立的信号灯操作可能都需要维护一个调整动作。 Linux 至少为每一个进程
的每一个信号灯数组都维护一个 sem_undo 的数据结构。如果请求的进程没有,就在需
要的时候为它创建一个。这个新的 sem_undo 数据结构同时在进程的 task_struct 数据
结构和信号灯队列的 semid_ds 数据结构的队列中排队。对信号灯队列中的信号灯执行
操作的时候,和这个操作值相抵消的值加到这个进程的 sem_undo 数据结构的调整队列
这个信号灯的条目上。所以,如果操作值为 2 ,那么这个就在这个信号灯的调整条目上
增加 -2 。
当进程被删除,比如退出的时候, Linux 遍历它的 sem_undo 数据结构组,并
实施对于信号灯数组的调整。如果删除信号灯,它的 sem_undo 数据结构仍旧停留在进
程的 task_struct 队列中,但是相应的信号灯数组标识符标记为无效。这种情况下,清除
信号灯的代码只是简单地废弃这个 sem_undo 数据结构。
http://3521632.blog.163.com/blog/static/110237933201032041353708/
以下例程
第一:先执行init.c初始化,让信号量集的第1个信号量值为1,当然电脑索引是从0开始的;
第二:再执行多个test.c
intit.c
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/sem.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <stdio.h>
- #include <string.h>
- int open_semque(void);
- void set_sem(int, int);
- #if 1
- union semun
- {
- int val;
- struct semid_ds buf;
- unsigned short *array;
- };
- #endif
- int main(int argc,char** argv)
- {
- int ret;
- int semque_id;
- semque_id = open_semque();
- set_sem(semque_id, 1);
- ret = semctl(semque_id, 0, GETVAL);
- printf("信号集中第一个信号量的值为:%d/n",ret);
- return 0;
- }
- int open_semque(void)
- {
//创建一个键- key_t key = ftok("./",100);
- if(key == -1)
- {
- perror("ftok/n");
- exit(1);
- }
- //创建信号量集,
- //IPC_CREAT 存在则打开,不存在则新建,
- //0666是权限
- //设置这个信号量集中包含几个信号量,设为1
- int semque_id = semget(key, 1,IPC_CREAT|0666);
- if(semque_id == -1)
- {
- perror("msgget/n");
- exit(1);
- }
- return semque_id;
- }
- void set_sem(int semque_id, int val)
- {
- //此联合体需要自己去创建,在初始化信号量时需要这个联合体;
- union semun sem_union;
- sem_union.val = val;
- if(semctl(semque_id, 0, SETVAL, sem_union) == -1)
- {
- perror("semctl_set/n");
- exit(1);
- }
- }
test.c
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/sem.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <stdio.h>
- #include <string.h>
- void v_sem(int);
- void p_sem(int);
- int open_semque(void);
- void set_sem(int, int);
- #if 1
- union semun
- {
- int val;
- struct semid_ds buf;
- unsigned short *array;
- };
- #endif
- int main(int argc,char** argv)
- {
- int ret;
- int semque_id;
- semque_id = open_semque();
- //set_sem(semque_id, 1);
- ret = semctl(semque_id, 0, GETVAL);
- printf("信号集中第一个信号量的值为:%d/n",ret);
- fputs("执行操作V/n",stdout);
- v_sem(semque_id);
- ret = semctl(semque_id, 0, GETVAL);
- printf("信号集中第一个信号量的值为:%d/n",ret);
- int second = 10;
- while(second)
- {
- sleep(1);
- printf("%ds/n",second);
- ret = semctl(semque_id, 0, GETVAL);
- printf("信号集中第一个信号量的值为:%d/n",ret);
- second--;
- }
- fputs("执行操作P/n",stdout);
- p_sem(semque_id);
- ret = semctl(semque_id, 0, GETVAL);
- printf("信号集中第一个信号量的值为:%d/n",ret);
- //semctl(semque_id, 0, IPC_RMID);
- return 0;
- }
- int open_semque(void)
- {
- key_t key = ftok("./",100);
- if(key == -1)
- {
- perror("ftok/n");
- exit(1);
- }
- int semque_id = semget(key, 1,IPC_CREAT|0666);
- if(semque_id == -1)
- {
- perror("msgget/n");
- exit(1);
- }
- return semque_id;
- }
- void set_sem(int semque_id, int val)
- {
- union semun sem_union;
- sem_union.val = val;
- if(semctl(semque_id, 0, SETVAL, sem_union) == -1)
- {
- perror("semctl_set/n");
- exit(1);
- }
- }
- void p_sem(int semque_id)
- {
- struct sembuf arry[1];
- arry[0].sem_num = 0;
- arry[0].sem_op = 1;
- //arry[0].sem_flg = SEM_UNDO;
- int ret;
- //需要通过结构体struct sembuf进行赋值
- if(ret = semop(semque_id, arry, 1))
- {
- perror("semop/n");
- exit(1);
- }
- }
- void v_sem(int semque_id)
- {
- struct sembuf arry[1];
- arry[0].sem_num = 0;
- arry[0].sem_op = -1;
- //arry[0].sem_flg = IPC_NOWAIT;
- arry[0].sem_flg = SEM_UNDO;
- int ret;
- if(ret = semop(semque_id, arry, 1))
- {
- perror("semop/n");
- exit(1);
- }
- }
原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/183569.html