什么是映射
动态连接库怎么实现的?
什么是写时复制?
内存映射怎么实现
mmap,munmap:
mmap将一个文件或者其它对象的数据映射到指定的内存。(通俗一点就是从其他地方指定的位置拷贝数据到本进程指定长度的地址当中)
mmap操作提供了一种机制,让用户程序直接访问设备内存,这种机制,相比较在用户空间和内核空间互相拷贝数据,效率更高。在要求高性能的应用中比较常用。
munmap执行相反的操作,删除特定内存区的对象映射。
#include <sys/mman.h>
void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
int munmap(void *start, size_t length);
start:映射区内存的起始地址,设置为0时表示由系统决定映射区的起始地址。
length:映射区内存的长度。注意,这个不是映射的数据长度。
为什么length=1,也可以映射正文件的内容:
prot:内存区保护标志,不能与文件的打开模式冲突。是以下的某个值,可以通过or运算(“|”)合理地组合在一起
PROT_EXEC //内存区内容可以被执行
PROT_READ //内存区内容可以被读取
PROT_WRITE //内存区可以被写入
PROT_NONE //内存区不可访问
flags:设置内存区的属性,MAP_SHARED----共享的,写入的内容可以写入文件,MAP_PRIVATE--本进程私有,写入的内容最终不会保存在文件中。
fd:文件描述符。
offset:被映射对象内容起始点。
注意:mmap返回的地址类型是void*,需要强转。
mmap失败返回MAP_FAILED(-1)
memcpy:
memory copy内存(数据)拷贝函数
void *memcpy(void *dest, const void *src, size_t n);
它的功能是从src的开始位置拷贝n个字节的数据到dest。如果dest存在数据,将会被覆盖。memcpy函数的返回值是dest的指针。memcpy函数定义在string.h头文件里。
void main()
{
char arr[10]="aaaaaaaa";
char* str="uiefcb";
memcpy(arr,str,6);
printf("%s\n",arr);
}
输出:uiefcbaa
mmap的实现
#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
#include <cstring>
using namespace std;
char* shm_ptr=nullptr;
int fd=-1;
int main(){
//1,打开要关联的文件,获得文件描述符
fd=open("shareFile.c",O_CREAT|O_RDWR,0666);
assert(fd!=-1);
//2,设置文件大小
int ret=ftruncate(fd,10);
assert(ret!=-1);
//3,文件映射,获取物理内存,返回内存首地址,返回的就是一个指针
shm_ptr=(char*)mmap(NULL,10,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
assert(shm_ptr!=MAP_FAILED);
//4,用指针向内存写入数据,内存中的数据会被保存到文件中
strcpy(shm_ptr,"success");
//5,关闭
close(fd);
munmap(shm_ptr,10);
return 0;
}
共享内存实现进程间共享文件对象--posix
#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
/*
*共享内存建立之后,进程想要使用,还要将共享内存和自己的虚拟地址建立关联
*申请--关
*
* */
using namespace std;
char* shm_ptr=nullptr;
int shm_fd=-1;
int main(){
//1,注意:指定的共享文件对象一定要以/开头,不同于open,这里不指定路径,因为这个共享文件
//对象只是暂时的使用,使用完之后如果文件本来存在,shm_unlink会清除共享时修改的内容,还原文件
//本来的数据,如果文件是被创建的,文件会被删除。
shm_fd=shm_open("/shareFile.c",O_CREAT|O_RDWR,0666);
assert(shm_fd!=-1);
//2,指定共享文件对象的大小
int ret=ftruncate(shm_fd,1024);
assert(ret!=-1);
//3,申请物理内存,将物理内存和共享文件对象相互关联,返回物理内存首地址
shm_ptr=(char*)mmap(NULL,1024,PROT_READ|PROT_WRITE,MAP_SHARED,shm_fd,0);
assert(shm_ptr!=MAP_FAILED);
pid_t pid=fork();
if(pid==0){
for(int i=0;i<10;++i)
cin>>shm_ptr[i];
sleep(10);
}
else if(pid>0){
sleep(20);
cout<<shm_ptr<<endl;
munmap(shm_ptr,1024);
shm_unlink("./shareFile.c");
}else return -1;
return 0;
}
注意:编译需要链接 -lrt
共享内存实现进程间共享文件对象2
//进程1--写数据
#include <iostream>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <assert.h>
#include <cstring>
using namespace std;
int main(){
//1,ftok(把一个已存在的路径名和一个整数标识符转换成IPC键值),注意返回的key不是指定数值,随
//机的
key_t key=ftok("./shareFile.c",1024);
assert(key!=-1);
cout<<key<<endl;
//2,创建或者获取共享内存,返回共享内存标识符
int shmid=shmget(key,1024,IPC_CREAT|0777);
//3,关联当前进程的虚拟地址空间--shmat,使用完后要用shmdt分离虚拟地址空间和物理内存
void* shm=shmat(shmid,NULL,0);
char* shm_ptr=(char*)shm;
memset(shm_ptr,0,1024);
for(int i=0;i<10;++i)
cin>>shm_ptr[i];
//4,使用完毕,解出映射
shmdt(shm_ptr);
return 0;
}
//进程2--读数据
#include <iostream>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <assert.h>
#include <cstring>
using namespace std;
int main(){
//1,ftok(把一个已存在的路径名和一个整数标识符转换成IPC键值)
key_t key=ftok("./shareFile.c",1024);
assert(key!=-1);
cout<<key<<endl;
//2,创建或者获取共享内存,返回共享内存标识符
int shmid=shmget(key,1024,IPC_CREAT|0777);
//3,关联当前进程的虚拟地址空间--shmat,使用完后要用shmdt分离虚拟地址空间和物理内存
void* shm=shmat(shmid,NULL,0);
char* shm_ptr=(char*)shm;
cout<<shm_ptr<<endl;
//4,使用完毕,解出映射
shmdt(shm_ptr);
return 0;
}