本片博客会粘贴部分代码,想要了解更多代码信息,可访问小编的GitHub关于本篇的代码
这里有涉及的mmap的知识
下图为共享内存原理图
因为共享内存是直接将申请来的一块物理内存映射到虚拟地址空间中,允许两个或多个进程共享,因此进行数据传输的时候相较于其它进程间通信方式,少了两步用户态与内核态数据拷贝的过程,因此共享内存是最快的进程间通信方式。
- 创建共享内存
int shmget(key_t key, size_t size, int shmflg);
key: 操作系统上ipc标识
size: 要创建的共享内存大小
shmflg:
IPC_CREAT|IPC_EXCL|0664
返回值:操作句柄 失败:-1
- 内存映射
void *shmat(int shmid, const void *shmaddr, int shmflg);
shmid: 操作句柄
shmaddr: 映射起始地址,NULL(操作系统分配)
shmflg: SHM_RDONLY–只读 否则读写
成功返回:映射的虚拟地址空间首地址
失败返回:(void*)-1
- 解除映射
int shmdt(const void *shmaddr);
shmaddr 共享内存的映射首地址
返回值:成功:0 失败:-1
- 删除共享内存
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
shmid: 句柄
cmd: IPC_RMID 删除
buf: 用于接收共享内存描述信息,不关心可以置空
操作系统:如果有进程依然与共享内存保持映射连接关系,那么共享内存将不会被立即删除,而是等最后一个映射断开后删除 ,在这期间,将拒绝其他进程映射。
服务端
/*这是共享内存的服务端,目的是:往共享内存写入数据后*/
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<sys/ipc.h>
#include<sys/shm.h>
//定义一个ipc标识符
#define KEY 0x520
int main()
{
umask(0);
//创建共享内存
//int shmget(key_t key, size_t size, int shmflg);
int shmid=-1;
shmid=shmget(KEY,520,IPC_CREAT|0664);
if(shmid<0){
perror("shmget error");
return -1;
}else
{
//映射到虚拟地址空间
//void *shmat(int shmid, const void *shmaddr, int shmflg);
void*shmhead=shmat(shmid,NULL,0);//shmaddr是要映射的起始地址,NULL表示由系统分配,
//shmflg如果是SHM_RDONLY则只读权限,否则读写
if(shmhead==(void*)-1)
{
perror("shmat error");
return -1;
}
while(1)
{
//映射成功,写操作
memset(shmhead,0x00,520);
scanf("%s",(char*)shmhead);
sleep(1);
}
//解除映射int shmdt(const void *shmaddr);
shmdt(shmhead);
//删除共享内存int shmctl(int shmid, int cmd, struct shmid_ds *buf);
shmctl(shmid,IPC_RMID,NULL);
}
return 0;
}
客户端
/*这是共享内存的客户端,目的:隔一秒钟,去共享内存取一次数据*/
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<sys/ipc.h>
#include<sys/shm.h>
//定义一个ipc标识符
#define KEY 0x520
int main()
{
umask(0);
//创建共享内存
//int shmget(key_t key, size_t size, int shmflg);
int shmid=shmget(KEY,520,IPC_CREAT|0664);
if(shmid<0){
perror("shmget error");
return -1;
}else
{
//映射到虚拟地址空间
//void *shmat(int shmid, const void *shmaddr, int shmflg);
void*shmhead=shmat(shmid,NULL,SHM_RDONLY);//shmaddr是要映射的起始地址,NULL表示由系统分配,
//shmflg如果是SHM_RDONLY则只读权限,否则读写
if(shmhead==(void*)-1)
{
perror("shmat error");
return -1;
}
while(1)
{
//映射成功,读取数据
printf("memshare:%s\n",(char*)shmhead);
sleep(1);
}
//解除映射int shmdt(const void *shmaddr);
shmdt(shmhead);
//删除共享内存int shmctl(int shmid, int cmd, struct shmid_ds *buf);
shmctl(shmid,IPC_RMID,NULL);
}
return 0;
}