共享内存原理
共享内存也是我们进程间通信内容当中的一个重点。什么是共享内存呢?
我们在学习虚拟地址空间的时候,在堆与栈之间有一片区域叫做共享区,而共享内存就是在物理内存内,将一片内存通过页表映射的方式映射至虚拟地址空间的共享区内,而不同进程都可以在其自己的虚拟地址空间上面的共享区通过映射访问到这片共享内存,这个时候不同进程相当于看到了同一片公共资源即共享内存,那么他们就可以在这片内存上进行通信。
共享内存区是最快的进程间通信的方式,因为一旦有映射能够访问到这片共享内存,那么这些进程间的数据传递不用再经过内核,不用经过系统调用来交换传递彼此间的数据。这样的速度会更快!
共享内存示意图
共享内存函数
shmget函数
功能:创建共享内存
原型:int shmget(key_t key, size_t size, int shmflg);
参数:
key:这里key如同之前消息队列一样,由ftok这个函数来返回,如果系统没有这个key,则直接返回key的内容,如果有返回-1,相当于共享内存的名字
size:共享内存的大小
shmflg:九个权限标志构成,用法与创建文件的时候mode模式标志一样
返回值:如果成功返回共享内存的标识码,失败返回-1
shmat函数
功能:将共享内存段连接到进程的地址空间
原型:void* shmat(int shmid, const void* shmaddr, int shmflg);
参数:
shmid:共享内存标识码
shmaddr:指定连接的地址
shmflg:它的两个可能取值是 SHM_RND和SHM_RDONLY
返回值:成功返回一个指针,指向共享内存的第一个字节,失败返回-1
shmdt函数
功能:将共享内存段与当前进程脱离
原型:int shmdt(const void* shmaddr);
参数:
shmaddr:有shmat所返回的指针
返回值:成功返回0,失败返回-1
注:这里的共享内存段与进程脱离,相当于取消了该进程页表对共享内存段的映射,而不是销毁这个共享内存段,此时其他没有脱离的进程仍旧可以使用这个共享内存段。
shmctl函数
功能:用于控制共享内存段
原型:int shmctl(int shmid, int cmd, struct shmid_ds * buf);
参数:
shmid:供向内存段的标识符
cmd:将要执行的操作
buf:指向一个保存着共享内存的模式和访问权限的数据结构
返回值:成功返回0,失败返回-1
这里利用共享内存基本操作函数来演示一下其效果:
//comm.h
#pragma once
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#define PATHNAME "/home/kaka"
#define PROJ_ID 0x6666
int creatShm(int size);
int getShm(int size);
int destroyShm(int shmid);
//comm.c
#include "comm.h"
int commShm(int size, int flag)
{
key_t key = ftok(PATHNAME, PROJ_ID);
if(key < 0)
{
printf("ftok error!\n");
return -1;
}
int shmid = shmget(key, size, flag);
if(shmid < 0)
{
printf("shmget error!\n");
return -1;
}
return shmid;
}
int creatShm(int size)
{
return commShm(size, IPC_CREAT | IPC_EXCL | 0666);
}
int getShm(int size)
{
return commShm(size, IPC_CREAT);
}
int destroyShm(int shmid)
{
if(shmctl(shmid, IPC_RMID, NULL) < 0)
{
printf("shmctl error!\n");
return -1;
}
return 0;
}
//server.c
#include "comm.h"
int main()
{
int shmid = creatShm(1024);
if(shmid < 0)
{
printf("shmid error!\n");
return -1;
}
char* addr = (char*)shmat(shmid, NULL, 0);
sleep(5);
int i = 0;
while(i < 26)
{
printf("client says# %s\n", addr);
sleep(1);
i++;
}
shmdt(addr);
sleep(2);
destroyShm(shmid);
return 0;
}
//client.c
#include "comm.h"
int main()
{
int shmid = getShm(1024);
if(shmid < 0)
{
printf("getShm error!\n");
return -1;
}
sleep(2);
char* addr = (char*)shmat(shmid, NULL, 0);
int i = 0;
while(i < 26)
{
addr[i] = 'A'+i;
i++;
sleep(1);
}
shmdt(addr);
sleep(2);
return 0;
}
欢迎大家共同讨论,如有错误及时联系作者指出,并改正。谢谢大家!