千家信息网

unix XSI IPC-信号量同步例程

发表于:2025-01-25 作者:千家信息网编辑
千家信息网最后更新 2025年01月25日,原理不多讲,可能查看unix 高级环境编程,只提一些注意点信号量系统限制信号量最大值 32767最多信号量集 128每个集中最多含有250信号量难理解的是标志位SEM_UNDO以下是个人愚见:首先是了
千家信息网最后更新 2025年01月25日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. int open_semque(void);
  9. void set_sem(int, int);
  10. #if 1

  11. union semun
  12. {
  13. int val;
  14. struct semid_ds buf;
  15. unsigned short *array;
  16. };
  17. #endif
  18. int main(int argc,char** argv)
  19. {
  20. int ret;
  21. int semque_id;
  22. semque_id = open_semque();
  23. set_sem(semque_id, 1);
  24. ret = semctl(semque_id, 0, GETVAL);
  25. printf("信号集中第一个信号量的值为:%d\n",ret);
  26. return 0;
  27. }
  28. int open_semque(void)
  29. {
    //创建一个键
  30. key_t key = ftok("./",100);
  31. if(key == -1)
  32. {
  33. perror("ftok\n");
  34. exit(1);
  35. }
  36. //创建信号量集,
  37. //IPC_CREAT 存在则打开,不存在则新建,
  38. //0666是权限
  39. //设置这个信号量集中包含几个信号量,设为1
  40. int semque_id = semget(key, 1,IPC_CREAT|0666);
  41. if(semque_id == -1)
  42. {
  43. perror("msgget\n");
  44. exit(1);
  45. }
  46. return semque_id;
  47. }
  48. void set_sem(int semque_id, int val)
  49. {
  50. //此联合体需要自己去创建,在初始化信号量时需要这个联合体;
  51. union semun sem_union;
  52. sem_union.val = val;
  53. if(semctl(semque_id, 0, SETVAL, sem_union) == -1)
  54. {
  55. perror("semctl_set\n");
  56. exit(1);
  57. }
  58. }



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