共享内存是最快的进程间通信形式,是通过调用系统接口(shmget)由操作系统开辟一块物理内存,然后通过页表映射到进程地址空间中,进而使得用户可以使用这块内存,两个进程间共用一块共享内存通过数据交互就可以建立通信。
未创建共享内存之前的虚拟内存和物理内存之间的联系

创建共享内存之后的虚拟内存和物理内存之间的联系
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x5X339Qj-1656584415666)(C:\Users\华哥\AppData\Roaming\Typora\typora-user-images\image-20220629224323893.png)]](https://1000bd.com/contentImg/2022/07/01/022140555.png)
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hdtuovKM-1656584415668)(C:\Users\华哥\AppData\Roaming\Typora\typora-user-images\image-20220629225840008.png)]](https://1000bd.com/contentImg/2022/07/01/022140806.png)

![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CiDzFixX-1656584415671)(C:\Users\华哥\AppData\Roaming\Typora\typora-user-images\image-20220629234723251.png)]](https://1000bd.com/contentImg/2022/07/01/022141338.png)
4、释放共享内存 通过函数int shmctl(int shmid, int cmd, struct shmid_ds *buf);释放共享内存 ;共享内存的生命周期是随着内核的而不是随着进程的结束而自动释放的(不同于文件),如果使用完不释放就会使得内存越来越少,造成内存泄漏,故申请的共享内存使用完后要记得释放
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AGPCMcJS-1656584415672)(C:\Users\华哥\AppData\Roaming\Typora\typora-user-images\image-20220629234820210.png)]](https://1000bd.com/contentImg/2022/07/01/022141538.png)
//输入指令
ipcs -m
//输入指令
ipcrm -m +[shmid]//shmid是共享内存id(用户)

具体的代码:
//头文件 包含用ftok()创建的key 需要的参数Pathname和proj_id
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<unistd.h>
#define pathname "/home/zh/nodeput/lesson23"
#define proj_id 0x36
#define SIZE 4096
-------------------------------------------
//client.c
#include"serve.h"
int main()
{
key_t key=ftok(pathname,proj_id);
if(key<0)
{
perror("ftok");
}
int shmid=shmget(key,SIZE,IPC_CREAT);//创建
char* mem=(char*)shmat(shmid,NULL,0);//挂接
//开始通信
int i=0;
while(1)
{
mem[i] = 'A'+ i;//这里是直接对开辟出来的共享内存进行使用 对其进行赋值操作 然后可以让另一个进程打印出来
i++;
mem[i]='\0';
sleep(1);
}
shmdt(mem);//去关联
shmctl(shmid,IPC_RMID,NULL);//释放
return 0;
}
-------------------------
//serve.c
#include"serve.h"
int main()
{
key_t key=ftok(pathname,proj_id);//生成key
if(key<0)
{
perror("ftok");
return 1;
}
int shmid= shmget(key,SIZE,IPC_CREAT|IPC_EXCL|0644);//通过key创建出共享内存
if(shmid<0)
{
perror("shmget");
return 2;
}
char* mem=(char*)shmat(shmid,NULL,0);//挂接共享内存
//开始通信
while(1)
{
printf("client sent: %s\n",mem);
sleep(1);
}
shmdt(mem);//去关联共享内存
shmctl(shmid,IPC_RMID,NULL);//释放共享内存
return 0;
}
int shmget(key_t key,size_t size,int shmflg)
第一个参数:key key 是通过ftok()函数根据pathname和proj_id创建出来的具有唯一映射关系的一个值,帮助操作系统用来标识一块共享内存
第二个参数:size size是我们要创建的共享内存的大小,我们看到的内存实际上是虚拟内存,是物理内存通过页表映射出来的,总是提到映射,可计算机到底是怎样将虚拟地址空间映射到实实在在的物理内存上的呢?这就要提到内存分段和分页模式了 这个转换过程有操作系统和CPU共同完成. 操作系统为CPU设置好页表 CPU通过MMU单元进行地址转换 简单的说,就是人为的把线性地址空间划分为一个一个4k的(几乎所有的PC上的操作都使用4KB大小的页)逻辑页,把内存页以同样的方法等分为固定大小的物理页 4kb,4096字节,为了更好的使用内存size最好是对齐4096 也就是说最好设置成4096的整数倍
第三个参数 :shmflg 主要是和一些标志有关,包括IPC_CEREAT和IPC_EXCL,这两个与open()的O_CREAT和O_EXCL类似。
**void shmat(int shmid, const void shmaddr, int shmflg);
**void shmat(int shmid, const void shmaddr, int shmflg)
*int shmctl(int shmid, int cmd, struct shmid_ds buf)
共享内存是创建好后就可以直接使用的,就像malloc 开辟的空间一样,不需要再另外调用函数来访问这块内存
而管道通信的时候创建好管道后需要调用系统接口read()和write()来访问管道文件的,这样就有数据在缓冲区之间的拷贝操作,进而使得效率变低
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bdMBg9KY-1656584415675)(1.1共享内存的介绍/image-20220630181015039.png)]](https://1000bd.com/contentImg/2022/07/01/022142225.png)
学习过管道我们知道管道是自带同步与互斥机制的,读写是不可以同时进行的。但是共享内存就不带这种机制,这就使得其数据的读写可以是同时进行的,要想实现类似同步与互斥的机制就需要用到锁或则信号量来解决