目录
共享内存:用于进程的数据共享,是最快的进程间通信方式
本质原理:共享内存本质来说就是一块物理内存,多个进程通将同一块物理内存都映射到自己的虚拟地址空间上,通过自己的虚拟地址空间进行访问,数据共享。
共享内存创建以后,在内核中是由标识符的,其他进程可以用过同一个标识符打开相同的共享内存,进行映射
为什么共享内存是最快的进程间通信方式:共享内存直接通过虚拟空间访问共享内存的数据,不像管道以及其他方式那样需要先将数据拷贝到内核态,获取数据时需要将数据从内核态中拷贝出,少了两次数据的拷贝,因此时最快的进程间的通方式。
共享内存的操作流程:
1.创建共享内存(开辟一块物理内存,并在内核中进行描述)
2.进程将共享内存映射到自己的虚拟地址空间上,并且获取映射后的首地址
3.对内存进行操作
4.不使用共享内存,则解除映射(不会删除共享内存,只是解除了共享内存与当前进程间的关系)
5.删除共享内存(共享内存有映射计数,只有为0时才会真的删除,否则不会被删除)
接口介绍:
创建共享内存
int shmget(key_t key,int size,int shmflag)------开辟一块物理内存,并在内核中进行描述
key: 共享内存的标识符,是一个整数,可以自己设置,可以以通过系统提供的接口设置
size:共享内存的大小
shmflag:共享内存的标志位 IPC_CREAT--若共享内存不存在则创建,存在则打开。IPC_EXCL与IPC_CREAT同时使用,若共享内存不存在则创建,存在则报错。
mode:共享内存的访问权限 0664
返回值:返回的共享内存在代码中的操作句柄,是一个数字,通过这个数字可以在内核中找到共享内存的描述
//创建共享内存
int shmid = shmget(IPC_KEY,32,IPC_CREAT | 0664);
if(shmid < 0)
{
perror("shmger error");
return -1;
}
映射到虚拟地址空间
void* shmat(int shmid, void *addr, int shmflag)
shmid: shmget接口返回的操作句柄
addr: 映射到虚拟地址空间的首地址,推荐NULL,由操作系统进行映射地址选择
shmflag: SHM_RDNOLY-只读/ 0 可读可写(前提时对共享内存具有相对的操作权限)
返回值:映射到虚拟地址空间的首地址,通过这个首地址可以访问这块共享内存
//映射
void * shm_start = shmat(shmid,NULL,0); // 0 可读可写
if(shm_start == (void*)-1)
{
perror("shmat error");
}
解除映射
int shmdt(void*shm_start);
shm_start:映射首地址,传入进来进行解除映射关系
//解除映射关系
shmdt(shm_start)
删除共享内存
int shmctl(int shmid,int cmd,struct shmid_ds *buf)
shmid: 共享内存的操作句柄
cmd: 具体要进行的操作 IPC_RMID --- 删除共享内存
buf: 同于设置/获取共享内存信息,用不到置NULL
//删除共享内存
shmctl(shmid,IPC_RMID,NULL);
ipcs 查看进程间通信资源
实例:两个进程同时访问一块共享内存
进程1 shm_read.c 从共享内存中读取数据
#include <stdio.h>
#include <unistd.h>
#include <sys/shm.h>
#include <string.h>
#define IPC_KEY 0x12345678
int main()
{
//创建共享内存
int shmid = shmget(IPC_KEY,32,IPC_CREAT | 0664);
if(shmid < 0)
{
perror("shmger error");
return -1;
}
//映射
void * shm_start = shmat(shmid,NULL,0); // 0 可读可写
if(shm_start == (void*)-1)
{
perror("shmat error");
}
//内存操作
while(1)
{
printf("shm:[%s]\n",(char*)shm_start);
sleep(1);
}
//解除映射关系
shmdt(shm_start);
//删除共享内存
shmctl(shmid,IPC_RMID,NULL);
进程2:shm_write.c 向共享内存中写入数据
#include <stdio.h>
#include <unistd.h>
#include <sys/shm.h>
#include <string.h>
#define IPC_KEY 0x12345678
int main()
{
//创建共享内存
int shmid = shmget(IPC_KEY,32,IPC_CREAT | 0664);
if(shmid < 0)
{
perror("shmger error");
return -1;
}
//映射
void * shm_start = shmat(shmid,NULL,0); // 0 可读可写
if(shm_start == (void*)-1)
{
perror("shmat error");
}
//内存操作
int i = 0;
while(1)
{
sprintf(shm_start,"woshinidie+%d",i++);
sleep(1);
}
//解除映射关系
shmdt(shm_start);
//删除共享内存
共享内存特性:
共享内存生命周期随内核
共享内存时最快的进程间通信方式
注意:
共享内存不自带同步与互斥,它的操作需要程序员的额外保护