共享内存是进程间的通信方式之一,进程之间内存共享
进程间的通信-共享内存共享内存机制共享内存机制是一种允许两个或多个进程(不相关或相关)访问同一个逻辑内存的机制。这是一种非常有效的数据共享和传输方式。不同进程之间共享的内存通常被安排为相同的物理内存。
两种常见的共享内存方式:System V版共享内存shmm多进程直接共享内存文件映射mmap如果一个文件需要频繁读写,那么就把它映射到内存。匿名映射特殊文件,为相关进程提供共享内存空间。为不相关的进程提供共享内存空间,并将一个普通文件映射到内存中。System V版本的共享内存shmm原理:
使用共享内存完成进程间通信,两个进程都可以通过虚拟地址空间映射到用户页表,再通过用户页表映射到物理内存的同一内存区域。
共享内存ftok的使用
角色:创建唯一的键来标识一块共享内存。(用不用)函数原型:key _ tftok (constchar * pathname,intproj _ id)参数:使用下面两个创建唯一的keypathname:proj_id:返回值:返回一个键。获取共享内存
角色:创建一个共享内存块,返回这个共享内存块的标识符shmid。Prototype: int shmget (key _ t key,size _ t size,int shmflg)参数描述:key:由ftok函数生成。Size:请求的共享内存的大小是4k的整数倍。因为x86系列cpu在linux系统下,所以基本上,内存也是4kb。Shmflg:权限标识。如果不存在,请参见-shmget (2)-Linux手册页IPC _ create: create。IPC_EXCL:与IPC_CREAT一起使用。如果存在,则创建失败。返回值:返回创建的共享内存块的标识符shmid。相关参考shmget(2)—Linux手册页shmat
功能:挂载共享内存,将共享内存连接到当前进程的地址空间,即允许这个进程访问一块共享内存。Prototype: void * shmat (int shmid,constvoid * shmaddr,int shmflg)参数:shmid:附加共享内存的id,由shmget函数获取。Shmaddr:一般为0,表示连接到内核选择的第一个可用地址。Shmflg: mark,通常为0。返回值:指向内存地址的指针。参考:shmat函数shmdt的使用
角色:非共享内存映射函数原型:int shmdt(const void * shmaddr);参数:shmaddr:shmat返回的内存指针。返回值:成功则返回0,失败则返回-1并设置errno。参考:shmdt-Linux API快速检查手册shmctl
功能:用于控制共享内存。原型:intshmctl (intshmid,intcmd,structshmid _ ds * buf);参数:参见shmctl(2)-Linux手册页shmid:共享内存标识码,由shmget获得。Cmd:要采取的操作(值:IPC_STAT,IPC_SET,IPC_RMID.).指向一个数据结构,它包含共享内存的模式状态和访问权限。相关内容:shmctl(2)-Linux手册页示例
#包括unistd.h
#包含stdlib.h
#包含stdio.h
#包含字符串. h
#包含sys/shm.h
结构连接状态{
int计数;
char IP[64];
};
int main(void){
void * shm=NULL
int shmid=0;//存储共享内存的ID
struct Conn_stat stat={0, 127 . 0 . 0 . 1 };
//创建共享内存
shmid=shmget((key_t)1234,sizeof(struct Conn_stat),0666 IPC _ CREAT);
if(shmid==-1){
fprintf(stderr, shmget失败\ n );
出口(1);
}
//将共享内存挂起到当前进程的地址空间
shm=shmat(shmid,(void*)0,0);
if(shm==(void*)-1){
fprintf(stderr, shmat失败\ n );
出口(2);
}
printf(内存附加在%p\n ,shm);
//设置共享内存
struct Conn _ stat * p=(struct Conn _ stat *)shm;
memcpy(p,stat,sizeof(struct Conn _ stat));
//修改共享内存中的数据
int I=0;
while((i ) 50){
p计数;
睡眠(1);
}
//将共享内存与当前进程分开
if(shmdt(shm)==-1){
fprintf(stderr, shmdt失败\ n );
出口(3);
}
返回0;
}shmread.c
#包括unistd.h
#包含stdlib.h
#包含stdio.h
#包含sys/shm.h
#包含字符串. h
#包含错误号h
结构连接状态{
int计数;
char IP[64];
};
int main(void){
void * shm=NULL//分配的共享内存的最初地址
struct Conn _ stat * stat=NULL
int shmid//共享内存标识符
//创建共享内存
shmid=shmget((key_t)1234,sizeof(struct Conn_stat),0666 IPC _ CREAT);
if(shmid==-1){
fprintf(stderr, shmget失败\ n );
退出(0);
}
//将共享内存挂至当前当前进程的地址空间。
shm=shmat(shmid,0,0);
if(shm==(void*)-1){
fprintf(stderr, shmat失败\ n );
出口(1);
}
printf( \ n内存附加在%p\n ,shm);
//设置共享内存
stat=(struct Conn _ stat *)shm;
int I=0;
while((i ) 10){
printf(ip=%s,count: %d\t\t\n ,stat- ip,stat-count);
睡眠(1);
}
//将共享内存与当前进程分开
if(shmdt(shm)==-1){
fprintf(stderr, shmdt失败\ n );
出口(2);
}
//删除共享内存
if(shmctl(shmid,IPC_RMID,0)==-1){
fprintf(stderr, shmctl(IPC_RMID)失败,原因:%s\n ,strerror(errno));
出口(3);
}
返回0;
}
内存映射共享I/O mmap原理:
将普通文件或其他对象映射到内存中。
使用普通文件提供的内存映射。使用特殊文件提供匿名内存映射。
使用mmap
作用:mmap是内存映射文件的一种方法,即将文件或其他对象映射到进程的地址空间,从而实现文件的磁盘地址与进程的虚拟地址空间中的一个虚拟地址之间的映射关系。原型:void * mmap (void * addr,size _ tlength,intprot,intflags,intfd,off _ toff set);参数:addr:指要映射的内存的起始地址,通常设置为NULL,表示映射成功后系统会自动选择地址并返回。长度:文件的多大部分被映射到内存。Prot:映射区域的保护方法。可以是以下几种方式的组合:PROT _执行:执行PROT _读取:读取PROT _写入:写入PROT _无:无法访问标志:影响映射区域的各种特性。MAP_SHARED:映射区数据对应文件,允许其他进程共享。MAP_PRIVATE:在区域内映射生成文件的副本,修改不同步的文件。MAP_ANONYMOUS:建立匿名映射。此时,参数fd被忽略,不涉及任何文件,并且映射区域不能与其他进程共享。MAP_DENYWRITE:允许对映射区域进行写操作,其他对文件的直接写操作将被拒绝。MAP_LOCKED:映射的区域被锁定,这意味着该区域不会被设置为swap。Fd:映射到内存的文件描述符。如果使用匿名内存映射,即在标志中设置MAP_ANONYMOUS,则fd设置为-1。有些系统不支持匿名内存映射,可以用fopen打开/dev/zero文件,然后映射文件,也可以达到匿名内存映射的效果。Offset:文件映射的偏移量,通常设置为0。对于从文件前面开始的对应,偏移量必须是页面大小的整数倍。返回值:Success:返回映射区域的指针。Fail: MAP_FAILED,其值为(void *)-1,设置了errno。参考:仔细分析mmap:它是什么,为什么以及如何使用munmap?
角色:Unmap。原型:intmunmap (void * addr,size _ t length);参数:addr:mmap返回的地址。长度:映射区域的大小。返回值:成功:返回0。失败:返回-1并设置错误号。参考:仔细分析mmap:它是什么,为什么以及如何使用示例map_write.c
#包含stdio.h
#包含stdlib.h
#包括unistd.h
#包含fcntl.h
#包含sys/types.h
#包含系统/统计信息
#include sys/mman.h
#包含字符串. h
结构连接状态{
int计数;
char IP[64];
};
//此过程创建一个用于写入的映射区域
int main(int argc,char* argv[]){
如果(argc!=2){
printf(用法:%s文件。\n ,argv[0]);
出口(1);
}
struct Conn_stat stat={0, 127 . 0 . 0 . 1 };
//打开文件
int fd=open(argv[1],O_RDWRO_CREATO_TRUNC,0644);
if(fd 0){
perror(‘开’);
出口(2);
}
//将文件截断到第二个参数的大小
ftruncate(fd,sizeof(struct Conn _ stat));
//创建结构大小的共享映射区域。我们可以把共享的映射区域看作一个数组区域。
结构连接状态* p=(结构连接状态*)mmap(NULL,sizeof(结构连接状态),PROT _读PROT写,映射_共享,fd,0);
if(p==MAP_FAILED){
perror(‘mmap’);
出口(3);
}
关闭(FD);//关闭不用的文件描述符
memcpy(p,stat,sizeof(struct Conn _ stat));
而(第30页){
p计数;
睡眠(1);
}
//解除映射
int ret=munmap(p,sizeof(struct Conn _ stat));
if(ret 0){
perror( MMU map );
出口(4);
}
返回0;
}map_read.c
#包含标准视频
#包含标准库
#包括unistd.h
#包含fcntl.h
#包含sys/types.h
#包含系统/统计信息
#include sys/mman.h
结构连接状态{
(同Internationalorganizations)国际组织计数;
char IP[64];
};
int main(int argc,char *argv[]){
如果(argc!=2){
printf(用法:%s文件. argv[0]);
出口(1);
}
//打开文件-只读,注意与写中的参数不同
int fd=open(argv[1],O_RDONLY,0644);
if(fd 0){
perror(’开);
出口(2);
}
结构连接状态状态
//注意与写中的参数不同
结构连接状态* p=(结构连接状态*)mmap(NULL,sizeof(结构连接状态),PROT _读取,映射_共享,fd,0);
if(p==MAP_FAILED){
perror(‘mmap’);
出口(3);
}
关闭(FD);
int I=0;
while((i ) 10){
printf(ip=%s,count: %d\t\t\n ,p- ip,p-count);
睡眠(1);
}
//接触映射
int ret=munmap(p,sizeof(stat));
if(ret 0){
perror( MMU map );
出口(4);
}
返回0;
}
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。