1. 共享内存原理
- 首先在物理内存当中创建一块物理内存
- 不同的进程通过页表映射,将同一块物理内存映射到自己的虚拟地址空间
- 不同的进程,操作进程虚拟地址,通过页表的映射,就相当于操作同一块内存,从而完成数据的交换
- 具体图示:
2. 创建共享内存
-
创建共享内存函数
int shmget(key_t key, size_t size, int shmflg ) ;
key:共享内存的标识符,用来标识一块共享内存,在操作系统当中,共享内存的标识符是不能重复的, 可以直接给32位的16进制数字。
size:共享内存的大小
shmflg:IPC_CREAT:如果key标识的共享内存不存在,则创建 IPC_EXCL | IPC_CREAT:如果key标识共享内存存在,则报错 权限:按位或8进制数字 0664 (这是共享内存的读写属性)
返回值:-1:失败了
小于0:则成功,返回的是,共享内存的操作句柄,后续是通过操作句柄来进行操作共享内存的
3. 查看共享内存
- 命令:ipca -m
- 查看介绍
- 共享内存的生命周期跟随操作系统的内核
4. 附加共享内存到进程
-
附加共享内存到进程相关函数
void *shmat ( int shmid, const void * shmaddr,int shmflg);
shmid:共享内存操作句柄,shmget的返回值
shmaddr:将共享内存附加到shmaddr,一般情况下,都不会自己去指定映射到共享区当中的那一段虚拟地址,而是传递NULL值,让操作系统去选择。
shmflg:标志将共享内存附加到进程以后,进程对共享内存的读写属性 0:读写 SHM_RDONLY :只读
返回值:[附加成功]:返回值为附加到虚拟进程中的虚拟地址。 [附加失败]:NULL
-
分离共享内存
int shmdt(const void *shmaddr);
shmaddr: 刚附加的时候,返回共享区的地址 -
共享内存操作函数
int fcntl(int fd,int cmd,…)
int shmctl (int shmid,int cmd,struct shmid_ds *buf );
shmid:共享内存操作句柄
cmd:IPC_STAT :获取共享内存参数 IPC_SET :设置共享内存属性 IPC_RMID :删除共享内存
struct shmid_ds :共享内存属性对应的结构体 ,删除时可以用NULL代替
5. 代码验证接口
- 首先是常见一个写进程,往共享内存当中写入内容
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/shm.h>
#define KEY 0x77777777
int main()
{
int shmid = shmget(KEY, 1024, IPC_CREAT | 0664);//创建共享内存
if(shmid < 0)
{
perror("shmget");
return 0;
}
//附加到当前的进程
void* addr = shmat(shmid, NULL, 0);
if(addr == NULL)
{
perror("shmat");
return 0;
}
//往共享内存写当中写
sprintf((char*)addr, "%s", "i am process");
shmdt(addr);
return 0;
}
- 之后再创建一个读进程,从共享内存当中读
#include <stdio.h>
#include <unistd.h>
#include <sys/shm.h>
#define KEY 0x77777777
int main()
{
int shmid = shmget(KEY, 1024, IPC_CREAT | 0664);
if(shmid < 0)
{
perror("shmget");
return 0;
}
//附加到当前的进程
void* addr = shmat(shmid, NULL, 0);
if(addr == NULL)
{
perror("shmat");
return 0;
}
printf("addr : %s\n", (char*)addr);
shmdt(addr);
return 0;
}
运行结果:
6. 共享内存特性
- 共享内存读取数据的时候,是采用拷贝的方式,而不是类似于管道的方式,将数据读走,也就是数据读过之后,数据还存在。
- 共享内存写的时候,采用覆盖写的方式。
- 如果删除了一个被进程附加的共享内存:
- 当前共享内存的标识符会被改变成0x00000000 ,并且共享内存的状态会变成dest(destroy)
- 我们通过ipsc -m这个命令可以查看到当前被删除共享内存的信息,说明被操作系统内核,描述该共享内存的结构体没有被释放,但是共享内存使用的空间已经被释放了,所以,附加进程如果再次操作共享内存,则有崩溃的风险
- 共享内存被创建以后,一直存在于内核当中,直到被删除或者系统关闭,并且读取后,内容仍然在其共享内存当中。