Linux——进程间通信(共享内存)

news/2024/7/7 20:44:42

一、共享内存

1、定义

       共享内存为多个进程之间共享和传递数据提供了一种有效的方式。共享内存是先在物理内存上申请一块空间,多个进程可以将其映射到自己的虚拟地址空间中。所有进程都可以访问共享内存中的地址,就好像它们是由malloc分配的一样。如果某个进程共享内存写入了数据,所做的改动将立刻被可以访问同一段共享内存的任何其他进程看到。

2、共享内存示例 

#include <sys/ipc.h>
 #include <sys/shm.h>
 #include <sys/types.h>

 int shmget(key_t key, size_t size, int shmflg);

 void* shmat(int shmid, const void *shmaddr, int shmflg);

 int shmdt(const void *shmaddr);

 int shmctl(int shmid, int cmd, struct shmid_ds *buf);

3、函数介绍

  •  shmget()用于创建或者获取共享内存
  •  shmget()成功返回共享内存的 ID, 失败返回-1
  •  key: 不同的进程使用相同的 key 值可以获取到同一个共享内存
  •  size: 创建共享内存时,指定要申请的共享内存空间大小

                   如果是获取已经存在的共享内存,则可以把size设置为0。

  •  shmflg: IPC_CREAT IPC_EXCL
  •  shmflg参数的使用和含义与semget系统调用的sem_flags参数相同。
  •  shmat()将申请的共享内存的物理内存映射到当前进程的虚拟地址空间上
  •  shmat()成功返回返回共享内存的首地址,失败返回 NULL
  •  shmaddr:一般给 NULL,由系统自动选择映射的虚拟地址空间
  •  shmflg: 一般给 0, 可以给 SHM_RDONLY 为只读模式,其他的为读写 
  •  shmdt()断开当前进程的 shmaddr 指向的共享内存映射
  •  shmdt()成功返回 0, 失败返回-1 
  •  shmctl()控制共享内存
  •  shmctl()成功返回 0,失败返回-1
  •  cmd: IPC_RMID 

4、例题理解

(1) 例1:进程a向共享内存写入数据,进程b从共享内存中读取数据并显示;

参考代码:

//a.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#include<unistd.h>
#include<sys/shm.h>

int main()
{
	int shmid=shmget((key_t)1234,256,IPC_CREAT|0600);
	assert(shmid!=-1);
 
	char* s=(char* )shmat(shmid,NULL,0);
	if(s==(char*)-1)//失败返回-1
	{
		exit(1);
	}
	strcpy(s,"hello");
	shmdt(s);
	exit(0);
}


//b.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#include<unistd.h>
#include<sys/shm.h>
 
int main()
{
	int shmid=shmget((key_t)1234,256,IPC_CREAT|0600);
	assert(shmid!=-1);
 
	char* s=(char* )shmat(shmid,NULL,0);
	if(s==(char*)-1)//失败返回-1
	{
		exit(1);
	}
	printf("%s",s);
	shmdt(s);
	shmctl(shmid,IPC_RMID,NULL);//IPC_RMID:删除,返回NULL
	exit(0);
}

(2)例2:进程a从键盘循环获取数据并拷贝到共享内存中,进程b从共享内存中获取并打印数据。要求进程a输入一次,进程b输出一次,若进程a不输入,进程b也不输出。

参考代码:

//sem.h
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<assert.h>
#include<sys/sem.h>
#define SEM1 0
#define SEM2 1
#define SEM_NUM 2
 
union semun
{
	int val;
};
 
void sem_init();
void sem_p(int index);//两个信号量,需要传参
void sem_v(int index);
void sem_destory();

//sem.c
#include"sem.h"
 
static int semid=-1;
void sem_init()
{
	semid=semget((key_t)1234,SEM_NUM,IPC_CREAT|IPC_EXCL|0600);
	if(semid==-1)
	{
		semid=semget((key_t)1234,SEM_NUM,IPC_EXCL|0600);
		if(semid==-1)
			perror("create sem error\n");
	}
	else
	{
		union semun a;
		int arr[SEM_NUM]={1,0};
		for(int i=0;i<SEM_NUM;i++)
		{
			a.val=arr[i];
			if(semctl(semid,i,SETVAL,a)==-1)
			{
				perror("semctl setval error!\n");
			}
		}
	}
}
 
void sem_p(int index)
{
	if(index<0||index>=SEM_NUM)
	{
		return;
	}
	struct sembuf buf;
	buf.sem_num=index;
	buf.sem_op=-1;
	buf.sem_flg=SEM_UNDO;
	if(semop(semid,&buf,1)==-1)
	{
		printf("sem p err\n");
	}
}
 
void sem_v(int index)
{
	if(index<0||index>=SEM_NUM)
	{
		return;
	}
	struct sembuf buf;
	buf.sem_num=index;
	buf.sem_op=1;
	buf.sem_flg=SEM_UNDO;
	if(semop(semid,&buf,1)==-1)
	{
		printf("sem v err\n");
	}
}
 
void sem_destory()
{
	if(semctl(semid,0,IPC_RMID)==-1)
	{
		printf("semctl del err\n");
	}
}


//a.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#include<unistd.h>
#include<sys/shm.h>
#include"sem.h"

int main()
{
	int shmid=shmget((key_t)1234,256,IPC_CREAT|0600);
	assert(shmid!=-1);
 
	char* s=(char* )shmat(shmid,NULL,0);
	if(s==(char*)-1)失败返回-1
	{
		exit(1);
	}
	sem_init();
	while(1)
	{
		printf("input:\n");
		char buff[128]={0};
		fgets(buff,128,stdin);
		sem_p(0);
		strcpy(s,buff);
		sem_v(1);
		if(strncmp(buff,"end",3)==0)
		{
			break;
		}		
		
	}
	shmdt(s);
	exit(0);
}

//b.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#include<unistd.h>
#include<sys/shm.h>
#include"sem.h"

int main()
{
	int shmid=shmget((key_t)1234,256,IPC_CREAT|0600);
	assert(shmid!=-1);
 
	char* s=(char* )shmat(shmid,NULL,0);
	if(s==(char*)-1)//失败返回-1
	{
		exit(1);
	}
	sem_init();
	while(1)
	{
		sem_p(1);
		if(strncmp(s,"end",3)==0)
		{
			break;
		}
		printf("read:%s\n",s);
		sem_v(0);
	}
	shmdt(s);
	sem_destory();
	exit(0);
}

如有错误,敬请指正。

您的收藏与点赞都是对我最大的鼓励和支持!


http://lihuaxi.xjx100.cn/news/176008.html

相关文章

vue3 框架学习概念笔记

文章目录前情提要框架设计概览命令式声明式小结虚拟dom性能运行时和编译时框架设计核心要素声明式描述UI渲染器组件的本质vue.js模板响应式系统概念完善的响应式系统响应式系统的调度计算属性Computedwatch 原理竞态问题非原始值的响应式方案javaScript 对象原始值的响应式方案…

双软认证需要什么条件

双软认证需要什么条件 双软认证一般指的是软件产品登记和软件企业认证。如果要申请软件企业认证则首先要进行软件产品检测和软件产品登记。成为“软件企业”应当包含四个程序&#xff1a;“软件著作权登记”、“软件产品测试”、“软件产品评估”、“软件企业评估”。 软件产…

《机械工程基础》复习题

一、填空题&#xff1a; 1. 构件由于受力不同&#xff0c;会产生不同的变形。基本形式有以下五种&#xff1a;1. 弯曲 &#xff1b;2. 扭转 &#xff1b; 3. 剪切 &#xff1b;4. 轴向拉伸 &#xff1b;5. 轴向压缩 。 2. 在机器中&#xff0c;运动的基本单元称之为__机构_ ___…

Caffeine《一》

《Caffeine&#xff08;Java顶级缓存组件&#xff09;一》 提示: 本材料只做个人学习参考,不作为系统的学习流程,请注意识别!!! 《Caffeine&#xff08;Java顶级缓存组件&#xff09;》《Caffeine&#xff08;Java顶级缓存组件&#xff09;一》1. Caffeine缓存概念1.1 缓存的分…

Red Eye Camera开发日记之API 移植I2C 和关键接口函数

API 说明文件里面有官方的移植指导&#xff0c;但我觉得可以把重点放在与 MLX90640 具体操作有关的几个函数上&#xff0c;而与标准 I2C 相关的函数和文件结构还是按照自己习惯的套路实现。这样更符合我们开发人员的可控性的习惯。步骤如下&#xff1a; 建立标准 I2C 文件 IIC…

【电力系统】CJAYA算法优化光伏模型SDM参数附matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …

java毕业生设计医院住院综合服务管理系统计算机源码+系统+mysql+调试部署+lw

java毕业生设计医院住院综合服务管理系统计算机源码系统mysql调试部署lw java毕业生设计医院住院综合服务管理系统计算机源码系统mysql调试部署lw本源码技术栈&#xff1a; 项目架构&#xff1a;B/S架构 开发语言&#xff1a;Java语言 开发软件&#xff1a;idea eclipse 前端技…

STM32F103的FSMC模块驱动LCD屏幕

以下内容为对正点原子的STM32F103STM32F103STM32F103精英板的FSMCFSMCFSMC模块驱动LCDLCDLCD屏幕例程的学习。做一个记录来加强对模块的认知。 FSMCFSMCFSMC的全称是FlexiblestaticmemorycontrollerFlexible\quad static\quad memory\quad controllerFlexiblestaticmemory…