找回密码
 立即注册
首页 业界区 安全 系统编程练习题---利用共享内存和信号量集,完成两个进 ...

系统编程练习题---利用共享内存和信号量集,完成两个进程之间的互斥通信

习和璧 2025-6-8 12:24:15
目录

  • 题目
  • 解析
  • 代码展示

    • process_A.c
    • process_B.c
    • process_C.c

  • 结果展示
  • 重要知识点记录

题目

设计一个程序,作为进程A,进程A专门创建一个信号量集,要求信号量集中有1个信号量,对信号量集合中的信号量进行设置,要求集合中的信号量的初值为1,然后再设计2个程序,分别是进程B和进程C,要求进程B和进程C使用进程A创建的信号量集合中的信号量实现互斥访问。  提示:进程A、进程B、进程C需要使用共享内存作为临界资源的访问。
解析

该题目核心设计思路是利用信号量集的P操作和V操作,实现进程B与进程C之间的互斥,避免进程B与进程C同时对共享内存段操作。三个进程文件具体分工如下:

  • 进程A用于创建并初始化信号量集与共享内存中的初始数据值
  • 进程B用于更改共享内存段中的数据值
  • 进程C用于输出共享内存段中的数据值
1.png

代码展示

process_A.c
  1. /*******************************************************************
  2. *
  3. *        file name:        process_A.c
  4. *        author         :  13316881233@163.com
  5. *        date         :  2024/05/28
  6. *        function :  该案例是掌握进程通信方式,主要是共享内存和信号量集的使用
  7. *                                进程A需要创建一个信号量集,该信号量集中有一个信号量,
  8. *                                 并要求该信号量的初值为1;进程A还需要创建一个共享内存段,
  9. *                                供给进程B和进程C进行访问操作
  10. *         note         :  None
  11. *   version  :
  12. *
  13. *        CopyRight (c)  2023-2024   13316881233@163.com   All Right Reseverd
  14. *
  15. * *****************************************************************/
  16. /****************************头文件**************************************/
  17. #include <stdio.h>
  18. #include <sys/shm.h>
  19. #include <sys/sem.h>
  20. #include <sys/types.h>
  21. #include <sys/ipc.h>
  22. #include <string.h>
  23. #include <errno.h>
  24. #include <stdlib.h>
  25. /****************************联合体**************************************/
  26. union semun
  27. {
  28.         int val;
  29.         struct semid_ds *buf;
  30.         unsigned short *array;
  31. } ;
  32. int main(int argc, char const *argv[])
  33. {
  34.         /****创建共享内存段,并完成数据的写入****/
  35.         //1. 申请共享内存段
  36.         int shm_id = shmget(ftok(".", 0xffffff01), 4, IPC_CREAT | IPC_EXCL | 0644);
  37.         if(shm_id == -1)
  38.         {
  39.                 fprintf(stderr, "shmget error, errno:%d, %s\n", errno, strerror(errno));
  40.                 shm_id = shmget(ftok(".", 0xffffff01), 4, 0644);
  41.         }
  42.         //2. 映射共享内存到进程A中
  43.         int *pshm = (int *)shmat(shm_id, NULL, 0);
  44.         if(pshm == (void*)-1)
  45.         {
  46.                 fprintf(stderr, "shmat error, errno:%d, %s\n", errno, strerror(errno));
  47.                 exit(-1);
  48.         }
  49.         //3. 向共享内存中写入数据
  50.         *pshm = 0;
  51.         //4. 分离共享内存段
  52.         int flag_dt = shmdt(pshm);
  53.         if(flag_dt == -1)
  54.         {
  55.                 fprintf(stderr, "shmdt error, errno:%d, %s\n", errno, strerror(errno));
  56.                 exit(-1);
  57.         }
  58.        
  59.         /****创建信号量集,并设置信号量集的信号量初值为1****/
  60.         //1. 创建信号量集
  61.         int sem_id = semget(ftok(".", 0xffffff01), 1, IPC_CREAT | IPC_EXCL | 0644);
  62.         if(sem_id == -1)
  63.         {
  64.                 fprintf(stderr, "sem_id error, errno:%d, %s\n", errno, strerror(errno));
  65.                 sem_id = semget(ftok(".", 0xffffff01), 1, 0644);
  66.         }
  67.         //2. 先获取信号集中的数据,再设置信号量初值为1
  68.         union semun arg;
  69.         arg.val = 1;
  70.         semctl(sem_id, 0,SETVAL,arg.val);
  71.         return 0;
  72. }
复制代码
process_B.c
  1. /*******************************************************************
  2. *
  3. *        file name:        process_B.c
  4. *        author         :  13316881233@163.com
  5. *        date         :  2024/05/28
  6. *        function :  该案例是掌握进程通信方式,主要是共享内存和信号量集的使用
  7. *                                需要将进程A创建的共享内存段映射到进程B中,方便后续写入数据;
  8. *                                进程B需要对进程A创建的信号量集交替进行P操作和V操作,来实现
  9. *                                对共享内存段中的数据互斥修改
  10. *         note         :  None
  11. *   version  :
  12. *
  13. *        CopyRight (c)  2023-2024   13316881233@163.com   All Right Reseverd
  14. *
  15. * *****************************************************************/
  16. /****************************头文件**************************************/
  17. #include <stdio.h>
  18. #include <sys/shm.h>
  19. #include <sys/sem.h>
  20. #include <sys/types.h>
  21. #include <sys/ipc.h>
  22. #include <string.h>
  23. #include <errno.h>
  24. #include <stdlib.h>
  25. #include <unistd.h>
  26. int main(int argc, char const *argv[])
  27. {
  28.         while(1)
  29.         {
  30.                 /****打开信号量集,完成P操作****/
  31.                 //1. 打开信号量集
  32.                 int sem_id = semget(ftok(".", 0xffffff01), 1, 0644);
  33.                 if(sem_id == -1)
  34.                 {
  35.                         fprintf(stderr, "sem_id error, errno:%d, %s\n", errno, strerror(errno));
  36.                         exit(-1);
  37.                 }
  38.                 //2. 定义结构体变量,并对结构体变量值完成相应配置
  39.                 struct sembuf semop_P;
  40.                 semop_P.sem_num = 0;        //该信号量集只有一个信号量,所以从下标0开始
  41.                 semop_P.sem_op = -1;        //操作值为负值,代表执行P操作,向信号量集申请资源
  42.                 semop_P.sem_flg = 0;        //由于题目要求进程B与进程C互斥,所以标志设为0,即默认阻塞模式
  43.                 //3. 对信号量集完成P操作
  44.                 semop(sem_id, &semop_P, 1);
  45.                 /****打开共享内存段,并完成数据的写入****/
  46.                 //1. 打开共享内存段
  47.                 int shm_id = shmget(ftok(".", 0xffffff01), 4, 0644);
  48.                 if(shm_id == -1)
  49.                 {
  50.                         fprintf(stderr, "shmget error, errno:%d, %s\n", errno, strerror(errno));
  51.                         exit(-2);
  52.                 }
  53.                 //2. 映射共享内存到进程B中
  54.                 int *pshm = (int *)shmat(shm_id, NULL, 0);
  55.                 if(pshm == (void*)-1)
  56.                 {
  57.                         fprintf(stderr, "shmat error, errno:%d, %s\n", errno, strerror(errno));
  58.                         exit(-3);
  59.                 }
  60.                 //3. 每次完成P操作后,将共享内存中的数据加一
  61.                 *pshm += 1;
  62.                 //4. 分离共享内存段
  63.                 int flag_dt = shmdt(pshm);
  64.                 if(flag_dt == -1)
  65.                 {
  66.                         fprintf(stderr, "shmdt error, errno:%d, %s\n", errno, strerror(errno));
  67.                         exit(-4);
  68.                 }
  69.                
  70.                 /****完成对共享内存中数据修改后,执行V操作****/
  71.                 //1. 定义结构体变量,并对结构体变量值完成相应配置
  72.                 struct sembuf semop_V;
  73.                 semop_V.sem_num = 0;        //该信号量集只有一个信号量,所以从下标0开始
  74.                 semop_V.sem_op = +1;        //操作值为正值,代表执行V操作,向信号量集归还资源
  75.                 semop_V.sem_flg = 0;        //由于题目要求进程B与进程C互斥,所以标志设为0,即默认阻塞模式
  76.                 //2. 对信号量集完成V操作
  77.                 semop(sem_id, &semop_V, 1);
  78.                 //为了方便观察结果,延迟一秒在进入循环
  79.                 sleep(1);
  80.         }
  81.         return 0;
  82. }
复制代码
process_C.c
  1. /*******************************************************************
  2. *
  3. *        file name:        process_C.c
  4. *        author         :  13316881233@163.com
  5. *        date         :  2024/05/28
  6. *        function :  该案例是掌握进程通信方式,主要是共享内存和信号量集的使用
  7. *                                需要将进程A创建的共享内存段映射到进程C中,方便后续读出数据;
  8. *                                进程C需要对进程A创建的信号量集交替进行P操作和V操作,来实现
  9. *                                对共享内存段中的数据互斥修改
  10. *         note         :  
  11. *             由于信号量集中的信号量初值设定为1,所以进程B与进程C的执行顺序
  12. *             会影响输出结果。若是想要从共享内存段中数据初值开始输出,则需要
  13. *             先执行进程C,在执行进程B
  14. *   version  :
  15. *
  16. *        CopyRight (c)  2023-2024   13316881233@163.com   All Right Reseverd
  17. *
  18. * *****************************************************************/
  19. /****************************头文件**************************************/
  20. #include <stdio.h>
  21. #include <sys/shm.h>
  22. #include <sys/sem.h>
  23. #include <sys/types.h>
  24. #include <sys/ipc.h>
  25. #include <string.h>
  26. #include <errno.h>
  27. #include <stdlib.h>
  28. #include <unistd.h>
  29. int main(int argc, char const *argv[])
  30. {
  31.         while(1)
  32.         {
  33.                 /****打开信号量集,完成P操作****/
  34.                 //1. 打开信号量集
  35.                 int sem_id = semget(ftok(".", 0xffffff01), 1, 0644);
  36.                 if(sem_id == -1)
  37.                 {
  38.                         fprintf(stderr, "sem_id error, errno:%d, %s\n", errno, strerror(errno));
  39.             exit(-1);
  40.         }
  41.         //2. 定义结构体变量,并对结构体变量值完成相应配置
  42.                 struct sembuf semop_P;
  43.                 semop_P.sem_num = 0;        //该信号量集只有一个信号量,所以从下标0开始
  44.                 semop_P.sem_op = -1;        //操作值为负值,代表执行P操作,向信号量集申请资源
  45.                 semop_P.sem_flg = 0;        //由于题目要求进程B与进程C互斥,所以标志设为0,即默认阻塞模式
  46.                 //3. 对信号量集完成P操作
  47.                 semop(sem_id, &semop_P, 1);
  48.                 /****打开共享内存段,并完成数据的输出****/
  49.                 //1. 打开共享内存段
  50.                 int shm_id = shmget(ftok(".", 0xffffff01), 4,  0644);
  51.                 if(shm_id == -1)
  52.                 {
  53.                         fprintf(stderr, "shmget error, errno:%d, %s\n", errno, strerror(errno));
  54.             exit(-2);
  55.         }
  56.         //2. 映射共享内存到进程B中
  57.                 int *pshm = (int *)shmat(shm_id, NULL, 0);
  58.                 if(pshm == (void*)-1)
  59.                 {
  60.                         fprintf(stderr, "shmat error, errno:%d, %s\n", errno, strerror(errno));
  61.                         exit(-3);
  62.                 }
  63.                 //3. 每次完成P操作后,将共享内存段中的数据输出到终端上
  64.         printf("data = %d\n", *pshm);
  65.         // 4. 分离共享内存段
  66.         int flag_dt = shmdt(pshm);
  67.                 if(flag_dt == -1)
  68.                 {
  69.                         fprintf(stderr, "shmdt error, errno:%d, %s\n", errno, strerror(errno));
  70.                         exit(-4);
  71.                 }
  72.                
  73.                 /****完成对共享内存中数据输出后,执行V操作****/
  74.                 //1. 定义结构体变量,并对结构体变量值完成相应配置
  75.                 struct sembuf semop_V;
  76.                 semop_V.sem_num = 0;        //该信号量集只有一个信号量,所以从下标0开始
  77.                 semop_V.sem_op = +1;        //操作值为正值,代表执行V操作,向信号量集归还资源
  78.                 semop_V.sem_flg = 0;        //由于题目要求进程B与进程C互斥,所以标志设为0,即默认阻塞模式
  79.                 //2. 对信号量集完成V操作
  80.                 semop(sem_id, &semop_V, 1);
  81.                 //为了方便观察结果,延迟一秒在进入循环
  82.                 sleep(1);
  83.         }
  84.         return 0;
  85. }
复制代码
结果展示

2.png

重要知识点记录

修改信号量集中的信号量的初值,需要使用到SETVAL标识,具体操作如下图:
3.png


来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册