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

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

时间:2024-05-28 20:24:52浏览次数:14  
标签:练习题 include errno 信号量 互斥 进程 sem 共享内存

目录

题目

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

解析

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

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

image

代码展示

process_A.c

/*******************************************************************
*
*	file name:	process_A.c
*	author	 :  [email protected]
*	date	 :  2024/05/28
*	function :  该案例是掌握进程通信方式,主要是共享内存和信号量集的使用
*				进程A需要创建一个信号量集,该信号量集中有一个信号量,
* 				并要求该信号量的初值为1;进程A还需要创建一个共享内存段,
*				供给进程B和进程C进行访问操作
* 	note	 :  None
*   version  :
*
*	CopyRight (c)  2023-2024   [email protected]   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	 :  [email protected]
*	date	 :  2024/05/28
*	function :  该案例是掌握进程通信方式,主要是共享内存和信号量集的使用
*				需要将进程A创建的共享内存段映射到进程B中,方便后续写入数据;
*				进程B需要对进程A创建的信号量集交替进行P操作和V操作,来实现
*				对共享内存段中的数据互斥修改
* 	note	 :  None
*   version  :
*
*	CopyRight (c)  2023-2024   [email protected]   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	 :  [email protected]
*	date	 :  2024/05/28
*	function :  该案例是掌握进程通信方式,主要是共享内存和信号量集的使用
*				需要将进程A创建的共享内存段映射到进程C中,方便后续读出数据;
*				进程C需要对进程A创建的信号量集交替进行P操作和V操作,来实现
*				对共享内存段中的数据互斥修改
* 	note	 :  
*             由于信号量集中的信号量初值设定为1,所以进程B与进程C的执行顺序
*             会影响输出结果。若是想要从共享内存段中数据初值开始输出,则需要
*             先执行进程C,在执行进程B
*   version  :
*
*	CopyRight (c)  2023-2024   [email protected]   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;
}

结果展示

image

重要知识点记录

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

image

标签:练习题,include,errno,信号量,互斥,进程,sem,共享内存
From: https://www.cnblogs.com/fly-home/p/18218764

相关文章

  • 信号量集与共享内存
    信号量集与共享内存​ 今日练习:设计一个程序,作为进程A,进程A专门创建一个信号量集,要求信号量集中有1个信号量,对信号量集合中的信号量进行设置,要求集合中的信号量的初值为1,然后再设计2个程序,分别是进程B和进程C,要求进程B和进程C使用进程A创建的信号量集合中的信号量实现互斥访问。......
  • A申请共享内存并对信号量进行初始化,然后进程B与C实现互斥
    练习:设计一个程序,作为进程A,进程A专门创建一个信号量集,要求信号量集中有1个信号量,对信号量集合中的信号量进行设置,要求集合中的信号量的初值为1,然后再设计2个程序,分别是进程B和进程C,要求进程B和进程C使用进程A创建的信号量集合中的信号量实现互斥访问。提示:进程A、进程B、进......
  • 利用信息量集实现互斥访问
    进程A用来生成信号集,并将其初值设为1(运行顺序为进程A->B->C)/**@Author:[email protected]*@Date:2024-05-0817:20:41*@LastEditors:[email protected]*@LastEditTime:2024-05-2818:47:38*/#include<stdio.h>#include<stdlib.h>#include<sys/......
  • 进程间同步(互斥锁)
    【一】什么是互斥锁互斥锁是一种用于多线程编程中控制对共享资源访问的机制限制当前时间段只能由当前进程使用,当前进程使用完成后才能其他进程继续使用基本原理是在对共享资源进行访问前加锁,使得其他线程无法访问该资源,当访问完成后再解锁,使得其他线程可以进行访问【......
  • 9. 子查询练习题
    1.查询和Zlotkey相同部门的员工姓名和工资selectfirst_name,last_name,salaryfromemployeesewheredepartment_id=(selectdepartment_id fromemployeese2 wherelast_name='Zlotkey' );2.查询工资比公司平均工资高的员工的员工号,姓名和工......
  • 共享内存练习题
    设计三个程序,要求三个程序申请一块共享内存,并分别映射到各自进程的地址空间,进程A和进程B对共享内存段中的数据进行修改,然后进程C不断输出共享内存段中的数据,并观察效果,要求实现进程间的互斥,避免竞争。进程A:/******************************************************************......
  • 消息队列练习题
    消息队列练习题进程A/**********************************************************************filename:mesqa.c*author:[email protected]*date:2024/5/28*function:接收进程b的信号,读出消......
  • 【.NET深呼吸】线程信号量(Semaphore)
    Semaphore类可以控制某个资源允许访问的线程数,Semaphore有命名式的,也有不命名的;如果不考虑跨进程工作,一般在代码中使用不命名方式即可。信号量有点类似于等待句柄,某个线程如果调用了WaitOne方法,这个线程就会暂停,并且等待有可用的信号量时才会继续执行;某个线程调用Release方法,就......
  • 消息队列练习题
    题目:要求进程A创建一条消息队列之后向进程B发送SIGUSR1信号,进程B收到该信号之后打开消息队列并把进程的PID作为消息写入到消息队列中,要求进程B在写入消息之后,发SIGUSR2信号给进程A,进程A收到该信号则从消息队列中读取消息并输出消息正文的内容。进程A的代码://构造用于接收消息......
  • 系统编程练习题----使用消息队列实现两个进程之间的通信
    目录题目思路代码展示进程A进程B结果展示题目要求进程A创建一条消息队列之后向进程B发送SIGUSR1信号,进程B收到该信号之后打开消息队列并写入一段信息作为消息写入到消息队列中,要求进程B在写入消息之后,发SIGUSR2信号给进程A,进程A收到该信号则从消息队列中读取消息并输出消息正文......