习和璧 发表于 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用于输出共享内存段中的数据值

代码展示

process_A.c

/*******************************************************************
*
*        file name:        process_A.c
*        author       :13316881233@163.com
*        date       :2024/05/28
*        function :该案例是掌握进程通信方式,主要是共享内存和信号量集的使用
*                                进程A需要创建一个信号量集,该信号量集中有一个信号量,
*                                 并要求该信号量的初值为1;进程A还需要创建一个共享内存段,
*                                供给进程B和进程C进行访问操作
*         note       :None
*   version:
*
*        CopyRight (c)2023-2024   13316881233@163.com   All Right Reseverd
*
* *****************************************************************/
/****************************头文件**************************************/

#include <stdio.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>

/****************************联合体**************************************/
union semun
{
        int val;
        struct semid_ds *buf;
        unsigned short *array;
} ;


int main(int argc, char const *argv[])
{
        /****创建共享内存段,并完成数据的写入****/
        //1. 申请共享内存段
        int shm_id = shmget(ftok(".", 0xffffff01), 4, IPC_CREAT | IPC_EXCL | 0644);
        if(shm_id == -1)
        {
                fprintf(stderr, "shmget error, errno:%d, %s\n", errno, strerror(errno));
                shm_id = shmget(ftok(".", 0xffffff01), 4, 0644);
        }
        //2. 映射共享内存到进程A中
        int *pshm = (int *)shmat(shm_id, NULL, 0);
        if(pshm == (void*)-1)
        {
                fprintf(stderr, "shmat error, errno:%d, %s\n", errno, strerror(errno));
                exit(-1);
        }
        //3. 向共享内存中写入数据
        *pshm = 0;
        //4. 分离共享内存段
        int flag_dt = shmdt(pshm);
        if(flag_dt == -1)
        {
                fprintf(stderr, "shmdt error, errno:%d, %s\n", errno, strerror(errno));
                exit(-1);
        }
       


        /****创建信号量集,并设置信号量集的信号量初值为1****/
        //1. 创建信号量集
        int sem_id = semget(ftok(".", 0xffffff01), 1, IPC_CREAT | IPC_EXCL | 0644);
        if(sem_id == -1)
        {
                fprintf(stderr, "sem_id error, errno:%d, %s\n", errno, strerror(errno));
                sem_id = semget(ftok(".", 0xffffff01), 1, 0644);
        }
        //2. 先获取信号集中的数据,再设置信号量初值为1
        union semun arg;
        arg.val = 1;
        semctl(sem_id, 0,SETVAL,arg.val);

        return 0;
}process_B.c

/*******************************************************************
*
*        file name:        process_B.c
*        author       :13316881233@163.com
*        date       :2024/05/28
*        function :该案例是掌握进程通信方式,主要是共享内存和信号量集的使用
*                                需要将进程A创建的共享内存段映射到进程B中,方便后续写入数据;
*                                进程B需要对进程A创建的信号量集交替进行P操作和V操作,来实现
*                                对共享内存段中的数据互斥修改
*         note       :None
*   version:
*
*        CopyRight (c)2023-2024   13316881233@163.com   All Right Reseverd
*
* *****************************************************************/
/****************************头文件**************************************/

#include <stdio.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>


int main(int argc, char const *argv[])
{
        while(1)
        {
                /****打开信号量集,完成P操作****/
                //1. 打开信号量集
                int sem_id = semget(ftok(".", 0xffffff01), 1, 0644);
                if(sem_id == -1)
                {
                        fprintf(stderr, "sem_id error, errno:%d, %s\n", errno, strerror(errno));
                        exit(-1);
                }
                //2. 定义结构体变量,并对结构体变量值完成相应配置
                struct sembuf semop_P;
                semop_P.sem_num = 0;        //该信号量集只有一个信号量,所以从下标0开始
                semop_P.sem_op = -1;        //操作值为负值,代表执行P操作,向信号量集申请资源
                semop_P.sem_flg = 0;        //由于题目要求进程B与进程C互斥,所以标志设为0,即默认阻塞模式
                //3. 对信号量集完成P操作
                semop(sem_id, &semop_P, 1);


                /****打开共享内存段,并完成数据的写入****/
                //1. 打开共享内存段
                int shm_id = shmget(ftok(".", 0xffffff01), 4, 0644);
                if(shm_id == -1)
                {
                        fprintf(stderr, "shmget error, errno:%d, %s\n", errno, strerror(errno));
                        exit(-2);
                }
                //2. 映射共享内存到进程B中
                int *pshm = (int *)shmat(shm_id, NULL, 0);
                if(pshm == (void*)-1)
                {
                        fprintf(stderr, "shmat error, errno:%d, %s\n", errno, strerror(errno));
                        exit(-3);
                }
                //3. 每次完成P操作后,将共享内存中的数据加一
                *pshm += 1;
                //4. 分离共享内存段
                int flag_dt = shmdt(pshm);
                if(flag_dt == -1)
                {
                        fprintf(stderr, "shmdt error, errno:%d, %s\n", errno, strerror(errno));
                        exit(-4);
                }
               
                /****完成对共享内存中数据修改后,执行V操作****/
                //1. 定义结构体变量,并对结构体变量值完成相应配置
                struct sembuf semop_V;
                semop_V.sem_num = 0;        //该信号量集只有一个信号量,所以从下标0开始
                semop_V.sem_op = +1;        //操作值为正值,代表执行V操作,向信号量集归还资源
                semop_V.sem_flg = 0;        //由于题目要求进程B与进程C互斥,所以标志设为0,即默认阻塞模式
                //2. 对信号量集完成V操作
                semop(sem_id, &semop_V, 1);

                //为了方便观察结果,延迟一秒在进入循环
                sleep(1);
        }

        return 0;
}process_C.c

/*******************************************************************
*
*        file name:        process_C.c
*        author       :13316881233@163.com
*        date       :2024/05/28
*        function :该案例是掌握进程通信方式,主要是共享内存和信号量集的使用
*                                需要将进程A创建的共享内存段映射到进程C中,方便后续读出数据;
*                                进程C需要对进程A创建的信号量集交替进行P操作和V操作,来实现
*                                对共享内存段中的数据互斥修改
*         note       :
*             由于信号量集中的信号量初值设定为1,所以进程B与进程C的执行顺序
*             会影响输出结果。若是想要从共享内存段中数据初值开始输出,则需要
*             先执行进程C,在执行进程B
*   version:
*
*        CopyRight (c)2023-2024   13316881233@163.com   All Right Reseverd
*
* *****************************************************************/
/****************************头文件**************************************/

#include <stdio.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>


int main(int argc, char const *argv[])
{
        while(1)
        {
                /****打开信号量集,完成P操作****/
                //1. 打开信号量集
                int sem_id = semget(ftok(".", 0xffffff01), 1, 0644);
                if(sem_id == -1)
                {
                        fprintf(stderr, "sem_id error, errno:%d, %s\n", errno, strerror(errno));
            exit(-1);
      }
      //2. 定义结构体变量,并对结构体变量值完成相应配置
                struct sembuf semop_P;
                semop_P.sem_num = 0;        //该信号量集只有一个信号量,所以从下标0开始
                semop_P.sem_op = -1;        //操作值为负值,代表执行P操作,向信号量集申请资源
                semop_P.sem_flg = 0;        //由于题目要求进程B与进程C互斥,所以标志设为0,即默认阻塞模式
                //3. 对信号量集完成P操作
                semop(sem_id, &semop_P, 1);

                /****打开共享内存段,并完成数据的输出****/
                //1. 打开共享内存段
                int shm_id = shmget(ftok(".", 0xffffff01), 4,0644);
                if(shm_id == -1)
                {
                        fprintf(stderr, "shmget error, errno:%d, %s\n", errno, strerror(errno));
            exit(-2);
      }
      //2. 映射共享内存到进程B中
                int *pshm = (int *)shmat(shm_id, NULL, 0);
                if(pshm == (void*)-1)
                {
                        fprintf(stderr, "shmat error, errno:%d, %s\n", errno, strerror(errno));
                        exit(-3);
                }
                //3. 每次完成P操作后,将共享内存段中的数据输出到终端上
      printf("data = %d\n", *pshm);
      // 4. 分离共享内存段
      int flag_dt = shmdt(pshm);
                if(flag_dt == -1)
                {
                        fprintf(stderr, "shmdt error, errno:%d, %s\n", errno, strerror(errno));
                        exit(-4);
                }
               
                /****完成对共享内存中数据输出后,执行V操作****/
                //1. 定义结构体变量,并对结构体变量值完成相应配置
                struct sembuf semop_V;
                semop_V.sem_num = 0;        //该信号量集只有一个信号量,所以从下标0开始
                semop_V.sem_op = +1;        //操作值为正值,代表执行V操作,向信号量集归还资源
                semop_V.sem_flg = 0;        //由于题目要求进程B与进程C互斥,所以标志设为0,即默认阻塞模式
                //2. 对信号量集完成V操作
                semop(sem_id, &semop_V, 1);

                //为了方便观察结果,延迟一秒在进入循环
                sleep(1);
        }

        return 0;
}结果展示


重要知识点记录

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


来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: 系统编程练习题---利用共享内存和信号量集,完成两个进程之间的互斥通信