unix XSI IPC-信号量同步例程

原理不多讲,可能查看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



  1. #include <sys/types.h> 
  2. #include <sys/ipc.h> 
  3. #include <sys/sem.h> 
  4. #include <stdlib.h> 
  5. #include <unistd.h> 
  6. #include <stdio.h> 
  7. #include <string.h> 
  8.  
  9. int open_semque(void); 
  10. void set_sem(int, int); 
  11. #if 1 

  12. union semun 
  13.       int val; 
  14.       struct semid_ds buf; 
  15.       unsigned short *array; 
  16. }; 
  17.  
  18. #endif 
  19.  
  20.  
  21. int main(int argc,char** argv) 
  22.       int ret; 
  23.        
  24.       int semque_id; 
  25.       semque_id = open_semque(); 
  26.         
  27.       set_sem(semque_id, 1); 
  28.       ret = semctl(semque_id, 0, GETVAL); 
  29.       printf("信号集中第一个信号量的值为:%d/n",ret); 
  30.        
  31.        
  32.       return 0; 
  33.  
  34.  
  35. int open_semque(void) 

  36. //创建一个键
  37.       key_t key = ftok("./",100); 
  38.        
  39.       if(key == -1) 
  40.       { 
  41.             perror("ftok/n"); 
  42.             exit(1); 
  43.       } 
  44. //创建信号量集,
  45. //IPC_CREAT 存在则打开,不存在则新建,
  46. //0666是权限
  47. //设置这个信号量集中包含几个信号量,设为1        
  48.       int semque_id = semget(key, 1,IPC_CREAT|0666); 
  49.       if(semque_id  == -1) 
  50.       { 
  51.             perror("msgget/n"); 
  52.             exit(1); 
  53.       } 
  54.        
  55.       return semque_id; 
  56.  
  57. void set_sem(int semque_id, int val) 
  58. //此联合体需要自己去创建,在初始化信号量时需要这个联合体;
  59.       union semun sem_union; 
  60.        
  61.       sem_union.val = val; 
  62.        
  63.      if(semctl(semque_id, 0, SETVAL, sem_union) == -1) 
  64.      { 
  65.             perror("semctl_set/n"); 
  66.             exit(1);      
  67.      } 




test.c



  1. #include <sys/types.h> 
  2. #include <sys/ipc.h> 
  3. #include <sys/sem.h> 
  4. #include <stdlib.h> 
  5. #include <unistd.h> 
  6. #include <stdio.h> 
  7. #include <string.h> 
  8.  
  9. void v_sem(int); 
  10. void p_sem(int); 
  11. int open_semque(void); 
  12. void set_sem(int, int); 
  13. #if 1 
  14. union semun 
  15.       int val; 
  16.       struct semid_ds buf; 
  17.       unsigned short *array; 
  18. }; 
  19.  
  20. #endif 
  21.  
  22.  
  23. int main(int argc,char** argv) 
  24.       int ret; 
  25.        
  26.       int semque_id; 
  27.       semque_id = open_semque(); 
  28.         
  29.       //set_sem(semque_id, 1); 
  30.       ret = semctl(semque_id, 0, GETVAL); 
  31.       printf("信号集中第一个信号量的值为:%d/n",ret); 
  32.        
  33.       fputs("执行操作V/n",stdout); 
  34.        
  35.       v_sem(semque_id); 
  36.       ret = semctl(semque_id, 0, GETVAL); 
  37.       printf("信号集中第一个信号量的值为:%d/n",ret); 
  38.        
  39.       int second = 10
  40.       while(second) 
  41.       { 
  42.             sleep(1); 
  43.             printf("%ds/n",second); 
  44.             ret = semctl(semque_id, 0, GETVAL); 
  45.             printf("信号集中第一个信号量的值为:%d/n",ret); 
  46.             second--; 
  47.       } 
  48.        
  49.  
  50.        
  51.       fputs("执行操作P/n",stdout); 
  52.       p_sem(semque_id); 
  53.       ret = semctl(semque_id, 0, GETVAL); 
  54.       printf("信号集中第一个信号量的值为:%d/n",ret); 
  55.  
  56.       //semctl(semque_id, 0, IPC_RMID); 
  57.  
  58.       return 0; 
  59.  
  60.  
  61. int open_semque(void) 
  62.       key_t key = ftok("./",100); 
  63.        
  64.       if(key == -1) 
  65.       { 
  66.             perror("ftok/n"); 
  67.             exit(1); 
  68.       } 
  69.        
  70.       int semque_id = semget(key, 1,IPC_CREAT|0666); 
  71.       if(semque_id  == -1) 
  72.       { 
  73.             perror("msgget/n"); 
  74.             exit(1); 
  75.       } 
  76.        
  77.       return semque_id; 
  78.  
  79. void set_sem(int semque_id, int val) 
  80.       union semun sem_union; 
  81.        
  82.       sem_union.val = val; 
  83.        
  84.      if(semctl(semque_id, 0, SETVAL, sem_union) == -1) 
  85.      { 
  86.             perror("semctl_set/n"); 
  87.             exit(1);      
  88.      } 
  89.  
  90. void p_sem(int semque_id) 
  91.       struct sembuf arry[1]; 
  92.       arry[0].sem_num = 0
  93.       arry[0].sem_op = 1
  94.       //arry[0].sem_flg = SEM_UNDO
  95.        
  96.       int ret; 
  97. //需要通过结构体struct sembuf进行赋值       
  98.       if(ret = semop(semque_id, arry, 1)) 
  99.       { 
  100.             perror("semop/n"); 
  101.             exit(1);        
  102.       } 
  103.  
  104.  
  105. void v_sem(int semque_id) 
  106.       struct sembuf arry[1]; 
  107.       arry[0].sem_num = 0
  108.       arry[0].sem_op = -1; 
  109.       //arry[0].sem_flg = IPC_NOWAIT
  110.       arry[0].sem_flg = SEM_UNDO
  111.        
  112.       int ret; 
  113.        
  114.       if(ret = semop(semque_id, arry, 1)) 
  115.       { 
  116.             perror("semop/n"); 
  117.             exit(1);        
  118.       } 

 

原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/183569.html

(0)
上一篇 2021年11月2日
下一篇 2021年11月2日

相关推荐

发表回复

登录后才能评论