linux——共享内存

1、概念

共享内存(Shared Memory)就是允许多个进程访问同一个内存空间,是在多个进程之间共享和传递数据最高效的方式。操作系统将不同进程之间共享内存安排为同一段物理内存,进程可以将共享内存连接到它们自己的地址空间中,如果某个进程修改了共享内存中的数据,其它的进程读到的数据也将会改变。

2、创建共享内存

复制代码
1.int shmget(key_t key, size_t size, int shmflg); 
//用来获取或创建共享内存 
参数: 
        key:IPC_PRIVATE 或 ftok的返回值 
        size:共享内存区大小 
        shmflg:同open函数的权限位,也可以用8进制表示法 
返回值: 
        成功:共享内存段标识符‐‐‐ID‐‐‐文件描述符 
        出错:‐1

#include<stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include<stdlib.h>
int main()
{
	int shmid;
	shmid = shmget(IPC_PRIVATE,128,0755);
	if(shmid<-1)
	{
		printf("create share memory failed\n");
		return -1;
	}
	printf("create share memory succeed shmid =%d\n",shmid);
	system("ipcs -m");
	return 0;
}

删除共享内存的指令:ipcrm -m <shmid>

3、单个进程读和写

复制代码
void *shmat(int shm_id, const void *shm_addr, int shmflg); 
//把共享内存连接映射到当前进程的地址空间 
参数: 
        shm_id:ID号 
        shm_addr:映射到的地址,NULL为系统自动完成的映射 
        shmflg: 
                SHM_RDONLY共享内存只读 
                默认是0,表示共享内存可读写 
返回值: 
        成功:映射后的地址 
        失败:NULL

#include<stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include<stdlib.h>
int main()
{
	int shmid;
    char *p;
	shmid = shmget(IPC_PRIVATE,128,0755);
	if(shmid<-1)
	{
		printf("create share memory failed\n");
		return -1;
	}
	printf("create share memory succeed shmid =%d\n",shmid);
	system("ipcs -m");
    
    p = (char *)shmat(shmid,NULL,0);
    if(p == NULL)
    {
        printf("shmat funtion failed\n");
        return -2;
    }
    //write to share memory
    fgets(p,128,stdin);
    //read from share memory
    printf("share memory data is %s\n",p);
    
	return 0;
}

管道和消息队列都是一次性读取的,读一次之后内容就被删除了,而共享内存不一样,不论都多少次,那条消息都在。

IPC 方式 读完是否消失 数据模型 适用场景
管道 / FIFO ✅ 读走就没 字节流 单向临时传输
消息队列 ✅ 读走就没 独立报文 (带 type) 收发消息、一对一
共享内存 ❌ 读一万次都在 内存区块 大数据、高频交互

3、删除地址映射

复制代码
int shmdt(const void *shmaddr); 
//将进程里的地址映射删除 
参数: 
        shmid:要操作的共享内存标识符 
返回值:  
        成功:0 
        出错:‐1 

#include<stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include<stdlib.h>
#include<string.h>
int main()
{
	int shmid;
    char *p;
	shmid = shmget(IPC_PRIVATE,128,0755);
	if(shmid<-1)
	{
		printf("create share memory failed\n");
		return -1;
	}
	printf("create share memory succeed shmid =%d\n",shmid);
	system("ipcs -m");
    
    p = (char *)shmat(shmid,NULL,0);
    if(p == NULL)
    {
        printf("shmat funtion failed\n");
        return -2;
    }
    //write to share memory
    fgets(p,128,stdin);
    //read from share memory
    printf("share memory data is %s\n",p);
    shmdt(p);
    memcp(p,"hello",5);
    
	return 0;
}

地址映射被删除了,所以最后写的hello,无处可写

4、删除共享内存对象

复制代码
int shmctl(int shm_id, int command, struct shmid_ds *buf); 
//删除共享内存对象 
参数: 
    shmid:要操作的共享内存标识符 
    cmd : 
        IPC_STAT  (获取对象属性)‐‐‐  实现了命令ipcs ‐m 
        IPC_SET (设置对象属性) 
        IPC_RMID (删除对象)   ‐‐‐实现了命令ipcrm ‐m 
    buf :指定IPC_STAT/IPC_SET时用以保存/设置属性 
返回值: 
    成功:0 
    出错:‐1

#include<stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include<stdlib.h>
int main()
{
	int shmid;
    char *p;
	shmid = shmget(IPC_PRIVATE,128,0755);
	if(shmid<-1)
	{
		printf("create share memory failed\n");
		return -1;
	}
	printf("create share memory succeed shmid =%d\n",shmid);
	system("ipcs -m");
    
    p = (char *)shmat(shmid,NULL,0);
    if(p == NULL)
    {
        printf("shmat funtion failed\n");
        return -2;
    }
    //write to share memory
    fgets(p,128,stdin);
    //read from share memory
    printf("share memory data is %s\n",p);
    shmdt(p);
    shctl(shmid,IPC_RMID,NULL);
    system("ipcs -m");
    
	return 0;
}

5、共享内存实现ipcrm

复制代码
#include<stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include<stdlib.h>
#include<string.h>

int main(int argc,char *argv[])
{
	int shmid;
	if(argc<3)
	{
		printf("input error\n");
		return -1;
	}
	if(strcmp(argv[1],"-m") == 0)
	{
		printf("delete share memory\n");
	}
	else 
	{
		return -2;
	}
	shmid = atoi(argv[2]);
	printf("delete share memory id:%d\n",shmid);

	shmctl(shmid,IPC_RMID,NULL);
	system("ipcs -m");
	return 0;
}

atoi是将输入的字符串转成数字,因为shmid是整型,而输入的是字符串

6、共享内存进程间通信

写端:

复制代码
#include<stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>

int main()
{
	int shmid;
	char *p;
	int pid;
	int key;

	key = ftok("a.c",1);
	if(key < 0)
	{
		printf("ftok failed\n");
		return -2;
	}
	printf("ftok succeed key:%x\n",key);

	shmid = shmget(key,128,IPC_CREAT|0777);
	if(shmid<0)
	{
		printf("create share memory failed\n");
		return -1;
	}
	printf("create share memory succeed shmid =%d\n",shmid);

	p = (char *)shmat(shmid,NULL,0);
	if(p == NULL)
	{
		printf("shmat funtion failed\n");
		return -3;
	}
	printf("please input to share memory:\n");
	//write to share memory
	fgets(p,128,stdin);
	sleep(3);

	shmdt(p);
	shmctl(shmid,IPC_RMID,0);
	return 0;
}

读端:

复制代码
#include<stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include<stdlib.h>
#include<string.h>

int main()
{
	int shmid;
	char *p;
	int pid;
	int key;

	key = ftok("a.c",1);
	if(key < 0)
	{
		printf("ftok failed\n");
		return -2;
	}
	printf("ftok succeed key:%x\n",key);

	shmid = shmget(key,128,0);
	if(shmid<0)
	{
		printf("create share memory failed\n");
		return -1;
	}
	printf("create share memory succeed shmid =%d\n",shmid);

	p = (char *)shmat(shmid,NULL,0);
	if(p == NULL)
	{
		printf("shmat funtion failed\n");
		return -3;
	}
	printf("share memory data:%s\n",p);
	shmdt(p);

	return 0;
}

注意,我在写端延迟了3秒再删除地址映射,也就是说,写端输入完之后,3秒之内要在另一个终端执行读端,否则将什么也读不到。

相关推荐
乌萨奇也要立志学C++10 小时前
【Linux】网络基础 从零理解网络通信:局域网、跨网传输与 Socket 预备知识
linux·服务器·网络
RisunJan12 小时前
Linux命令-slabtop(实时显示内核 slab 缓存信息)
linux
蚰蜒螟14 小时前
从内核源码看Linux启动:chroot、execve与MS_MOVE的协奏曲
linux·服务器·网络
酷可达拉斯14 小时前
自动化运维-ansible配置文件与主机清单
linux·运维·自动化·ansible
影视飓风TIM15 小时前
Linux下C语言缓冲区原理 + Git版本控制
linux·c语言·git
来者皆善15 小时前
ZYNQ linux上使用 USB CDC ACM
linux·运维·服务器
Dawn-bit17 小时前
Linux磁盘分区与Swap和磁盘故障查询
linux·运维·服务器·网络·云计算
无足鸟ICT18 小时前
【RHCA+】$[]
linux·运维·服务器
运维技术小记18 小时前
国产化环境配置 VNC 远程桌面:麒麟 V10 实战
linux·运维·服务器
xiaoye-duck19 小时前
《Linux系统编程》Linux 系统多线程(八): C++ 高并发线程池全链路深度解析与从零手撕实现
linux·c++·线程池