【Linux】应用篇十二--共享内存



一、内存映射

使一个磁盘文件内存中一个缓冲区相映射,进程可以像访问普通内存一样对文件进行访问,不必再调用read,write
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
优点:
实现了用户空间内核空间的高效交互方式


二、内存映射使用

void *mmap(void *addr, size_t length, int prot, 
int flags, int fd, off_t offset);

创建共享内存映射
成功返回创建的映射区首地址失败返回MAP_FAILED( ((void *) -1)),设置errno

  • addr:指定要映射的内存地址,一般设置为 NULL 让操作系统自动选择合适的内存地址。
  • length:必须>0。映射地址空间的字节数,它从被映射文件开头 offset 个字节开始算起。
  • prot:指定共享内存的访问权限。可取如下几个值的可选:PROT_READ(可读), PROT_WRITE(可写), PROT_EXEC(可执行), PROT_NONE(不可访问)。
  • flags:由以下几个常值指定:MAP_SHARED(共享的) MAP_PRIVATE(私有的),MAP_FIXED(表示必须使用 start 参数作为开始地址,如果失败不进行修正),其中,MAP_SHARED , MAP_PRIVATE必选其一,而 MAP_FIXED 则不推荐使用。MAP_ANONYMOUS(匿名映射,用于血缘关系进程间通信)
  • fd:表示要映射的文件句柄。如果匿名映射-1
  • offset:表示映射文件的偏移量,一般设置为 0 表示从文件头部开始映射

三、内存映射注意事项

  • (1) 创建映射区的过程中,隐含着一次对映射文件读操作,将文件内容读取映射区
  • (2) MAP_SHARED时,要求:映射区的权限<= 文件打开的权限(出于对映射区的保护),如果不满足报非法参数(Invalid argument)错误。
    MAP_PRIVATE时候,mmap中的权限是对内存的限制,只需要文件有读权限即可,操作只在内存有效,不会写到物理磁盘,且不能在进程间共享
  • (3) 映射区的释放文件关闭无关,只要映射建立成功,文件可以立即关闭。
  • (4) 用于映射的文件大小必须>0,当映射文件大小为0时,指定非0大小创建映射区,访问映射地址会报总线错误,指定0大小创建映射区,报非法参数错误(Invalid argument)
  • (5) 文件偏移量必须为0或者4K整数倍(不是会报非法参数Invalid argument错误).
  • (6)映射大小可以大于文件大小,但只能访问文件page的内存地址,否则报总线错误 ,超出映射的内存大小报段错误.
    在这里插入图片描述
    在这里插入图片描述
  • (7)mmap创建映射区出错概率非常高一定要检查返回值,确保映射区建立成功再进行后续操作。

四、释放映射

int munmap(void *addr, size_t length);

返回值:成功返回0败返回-1,并设置errno值。

  • addr:调用mmap函数成功返回的映射区首地址
  • length:映射区大小(即:mmap函数的第二个参数)

示例:
写共享文件:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/mman.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>

int main(int argc, const char *argv[])
{
	int len,fd = open("1.txt", O_RDWR);
	void *map;
	if(fd == -1)
	{
		perror("open:");
		return -1;
	}

	len = lseek(fd, 0, SEEK_END);
	map = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
	if(map == MAP_FAILED)
	{
		perror("mmap:");
	}

	while(1)
	{
		memcpy(map++, "a", 1);
		sleep(1);
	}
	return 0;
}

读共享文件:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/mman.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>

int main(int argc, const char *argv[])
{
	int len,fd = open("1.txt", O_RDWR);
	void *map;
	if(fd == -1)
	{
		perror("open:");
		return -1;
	}

	len = lseek(fd, 0, SEEK_END);
	map = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
	if(map == MAP_FAILED)
	{
		perror("mmap:");
	}

	while(1)
	{
		printf("%s\n", (char *)map);
		sleep(1);
	}
	return 0;
}

五、System V共享内存

IPC 的key

在这里插入图片描述


ftok函数

 key_t  ftok(const char *path,  int id);
  • ·参数path是指定的文件名,这个文件必须是存在的而且可以访问的。
  • id子序号,它是一个8bit的整数。即范围是0~255
  • 当函数执行成功,则会返回key_t键值,否则返回-1
  • 在一般的UNIX中,通常是将文件的索引节点取出,然后在前面加上子序号就得到key_t的值。

创建步骤

system V 共享内存使用步骤:

  • 创建/打开共享内存
  • 映射共享内存,即把指定的共享内存映射到进程的地址空间用于访问
  • 读写共享内存
  • 撤销共享内存映射
  • 删除共享内存对象

共享内存创建

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

共享内存映射

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

第二个参数一般写NULL,表示自动映射
第三参数一般写0 ,表示可读写

共享内存撤销

 int  shmdt(void *shmaddr);

撤销后,内存地址不可再访问。

共享内存控制

int  shmctl(int shmid, int cmd, struct shmid_ds *buf);
shmctl(shmid, IPC_RMID, NULL);删除共享内存

示例:
写:

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

int main(int argc, const char *argv[])
{
	key_t key;
	int shmid;
	void *buf;
	if((key = ftok("keytest", 100) == -1))
	{
		perror("ftok:");
		exit(-1);
	}

	printf("%d\n", key);
	if((shmid = shmget(key, 512, IPC_CREAT|0666)) == -1)
	{
		perror("shmget:");
		exit(-1);
	}

	printf("%d\n",shmid);
	buf = shmat(shmid, NULL, 0);
	strcpy(buf, "hello world");

	while(1)
	{
		sleep(1);
	}
	return 0;
}

读:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/ipc.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/shm.h>



int main(int argc, const char *argv[])
{
	key_t key;
	int shmid;
	void *buf;
	if((key = ftok("keytest", 100) == -1))
	{
		perror("ftok:");
		exit(-1);
	}

	printf("%d\n",key);
	
	buf = shmat(32822, NULL, 0);
	printf("%s\n", (char *)buf);
	
	shmdt(buf);
	shmctl(32822, IPC_RMID, NULL);

	return 0;
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

修成真

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值