LV5进程、线程和进程间通信(7)-共享内存

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

目录

前言

1.内存映射概念

2.内存映射使用

2.1函数定义:

3.内存映射注意事项

4.mmap()映射的种类

1.基于文件的映射

2.匿名映射

5.systemV共享内存

5.1了解SYSTEM V共享内存概念

​编辑2.共享内存使用步骤

3.ftok函数创建Key

​编辑4.创建/打开共享内存

5.映射共享内存

6.共享内存读写

7.共享内存控制

总结



前言


1.内存映射概念

共享内存可以通过mmap()映射普通文件

使磁盘文件与内存的一个缓冲区进行映射,进程可以像访问普通内存一样访问磁盘文件,不必再调用write和read

2.内存映射使用

上面图二就是利用了共享内存概念

2.1函数定义:

void *mmap(void *addr, size_ t length, int prot, int flags, int fd, off t offset);

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

参数说明:


start:指定要映射的内存地址,一般设置为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则不推荐使用。MAPANONYMOUS (匿名映射,用于血缘关系进程间通信)
fd:表示要映射的文件句柄。如果匿名映射写-1。
offset:表示映射文件的偏移量,一般设置为0表示从文件头部开始映射。

3.内存映射注意事项

注意事项:

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

 图中从左到右:

阴影部分可以写入到磁盘,page2剩余部分只能写入到内存,page3-4总线错误,最后是段错误

#include<stdio.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[])
{
	void *addr;
	int fd;
	fd = open("1.txt",O_RDWR);
	if(fd < 0){
		perror("open:");
		return 0;
	}
    //根据定位函数,返回文件大小
    //int len = lseek(fd,0,SEEK_END);
	addr = mmap(NULL,16000,PROT_WRITE|PROT_READ,MAP_SHARED,fd,0);
	if(addr == MAP_FAILED){
		perror("mmap:");
	}
	//close(fd);
	//映射区创建成功后,其释放与文件关闭无关

    //注意:写入的字节大小,必须<=1.txt文件的大小
    //addr指针运算,分成四段,对应上面的图描述
    //0-len,len-4000,4000-16000,>16000
	//memcpy(addr+16000,"abcdefg",7);

    memcpy(addr,"abcdefg",7);
	printf("%s\n",(char*)addr);
	return 0;
}

//注意:写入的字节大小,必须 <= 1.txt文件的字节大小,不然写入的数据不全

4.mmap()映射的种类

举例完成进程间通信

1.基于文件的映射

//写
#include<stdio.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[])
{
	void *addr;
	int fd;
	fd = open("1.txt",O_RDWR);
	if(fd < 0){
		perror("open:");
		return 0;
	}
	//根据定位函数,返回文件大小
	//int len = lseek(fd,0,SEEK_END);
	addr = mmap(NULL,2048,PROT_WRITE|PROT_READ,MAP_SHARED,fd,0);
	if(addr == MAP_FAILED){
		perror("mmap:");
	}
	close(fd);
	int i;
	for(i = 0;i<2048;i++){
	memcpy(addr+i,"a",1);
	sleep(1);
	}
	return 0;
}

//读
#include<stdio.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[])
{
	void *addr;
	int fd;
	fd = open("1.txt",O_RDWR);
	if(fd < 0){
		perror("open:");
		return 0;
	}
	//根据定位函数,返回文件大小
	//int len = lseek(fd,0,SEEK_END);
	printf("%s\n",(char*)(addr+5000));
	addr = mmap(NULL,2048,PROT_WRITE|PROT_READ,MAP_SHARED,fd,0);
	if(addr == MAP_FAILED){
		perror("mmap:");
	}
	close(fd);

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

2.匿名映射

#include<stdio.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[])
{
	void *addr;
	pid_t pid;
	//根据定位函数,返回文件大小
	//int len = lseek(fd,0,SEEK_END);
	addr = mmap(NULL,2048,PROT_WRITE|PROT_READ,MAP_SHARED|MAP_ANONYMOUS,-1,0);
	if(addr == MAP_FAILED){
		perror("mmap:");
	}
	pid = fork();
	if(pid > 0){
	memcpy(addr,"hhhhh",5);
	wait(NULL);
	}else if(pid == 0){
	sleep(1);
	printf("result=%s\n",(char*)addr);
	}else{
	perror("fork:");
	}
	return 0;
}

5.systemV共享内存

5.1了解SYSTEM V共享内存概念


2.共享内存使用步骤

 

 共享内存使用步骤
1.生成key
2.创建/打开共享内存
3.映射共享内存,即把指定的共享内存映射到进程的地址空间用于访问
4.读写共享内存
5.撤销共享内存映射
6.删除共享内存对象

3.ftok函数创建Key

key = ftok("keytest",100);

ftok函数是根据fname和id来创建一个关键字(类型为 key_t),此关键字在创建信号量,创建消息队列的时候都需要使用。

其中fname必须是一个存在的可访问的路径或文件,id必须不得为0


4.创建/打开共享内存

共享内存创建- shmget
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_ t key, int size, int shmflg);
➢成功时返回共享内存的id,失败时返回EOF

➢size是共享存储区字节数
➢key和共享内存关联的key, IPC PRIVATE或ftok生成
➢shmflg共享内存标志位IPC CREAT|0666

注意: IPCS指令    可以查看当前的共享内存,消息队列和信号量数组

5.映射共享内存

共享内存映射一shmat
#include <sys/ipc.h>
#include < sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);

➢成功时返回映射后的地址, 失败时返回(yoid *)-1
shmid要映射的共享内存id
shmaddr映射后的地址,NULL表示由系统自动映射
➢shmflg 标志位0表示可读写; SHM_ RDONLY表示只读

6.共享内存读写

见代码

7.共享内存控制

共享内存撤销映射- shmdt
#include <sys/ipc.h>
#include <sys/shm.h>
int shmdt(void *shmaddr);

➢成功时返回0,失败时返回EOF
➢不使用共享内存时应撤销映射
➢进程结束时自动撤销

共享内存删除。shmctl
#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid ds *buf);

成功时返回0,失败时返回EOF
shmid要操作的共享内存的id
➢cmd要执行的操作IPC STAT IPC SET IPC RMID
➢buf 保存或设置共享内存属性的地址

代码演示:进程间通信

//**************写*****************
#include <sys/types .h>
#include <sys/ ipc.h>
#include <stdio.h>
#include <sys/shm. h>
#include <string.h>

int main(){
    key_ t key;
    int shmid;
    char *buf;
    //1.获得ipc对象id
    key = ftok("keytest",100);
    if (key<0){
        perror("ftok" );
        return 0 ;
    }
printf("key=%&x\n",key);
    //2.创建内存,返回共享内存id
shmid = shmget (key,512, IPC CREAT |0666) ;
    if(shmid<0){
        perror("shmget") ;
        return 0;
    }
printf ("shmid=%d\n",shmid) ;
//3.共享内存映射,返回映射后的地址
buf = shmat( shmid,NULL,0);
    if(buf<0){
        perror("shmat");
        return 0;
    }
//4.写内存
strcpy(buf,"hello world");


}
//**************读*****************
#include <sys/types .h>
#include <sys/ ipc.h>
#include <stdio.h>
#include <sys/shm. h>
#include <string.h>

int main(){
    key_ t key;
    int shmid;
    char *buf;
    //1.获得ipc对象id
    key = ftok("keytest",100);
    if (key<0){
        perror("ftok" );
        return 0 ;
    }
printf("key=%&x\n",key);
    //2.获得shmid
shmid = shmget (key,512,0666) ;
    if(shmid<0){
        perror("shmget") ;
        return 0;
    }
printf ("shmid=%d\n",shmid) ;
//3.共享内存映射,返回映射后的地址
buf = shmat(shmid,NULL,0);
    if(buf<0){
        perror("shmat");
        return 0;
    }
//4.打印
printf("share mem = %s\n",buf);
//5.撤销映射==>多线程时,方便其他线程可以使用共享内存,且删除前必须线程全部撤销完
//shmdt(buf);
//6.删除共享内存空间
//shmctl(shmid,IPC_REID,NULL);

}

总结

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值