进程间通信----------共享内存

共享内存的原理

描述共享内存

共享内存就是借助同一块物理内存映射不同的虚拟地址空间,不同的虚拟地址空间代表着不同的进程,所以多个进程都能看到这一块内存,那么就可以同时对这块内存读写操作。
我们画张图感受一下:
这里写图片描述

组织共享内存

共享内存是一块内存,它的数据结构中都有以下数据
这里写图片描述

使用共享内存

相关函数

shmget函数:用来创建共享内存

int shmget(key_t key,size_t size,int shmflg);
//key共享内存段的名字
//size:共享内存大小(返回的大小等于size向上取整到4k的整数倍例如size=4097,那么返回的内存大小为8k即为两页)
//shmflg:权限
//返回值:成功返回一个非负整数(内存标识码),失败返回-1;

shmat函数:将共享内存连接到进程地址空间

void* shmat(int shmid,const void* shmaddr,int shmflg);
//shmid:共享内存标识码
//shmaddr:连接的地址
//shmflg:有两个取值可能是SHM_RND和SHM_RDONLY
//返回值:成功返回一个指针,指向共享内存第一个字节,失败返回-1

说明:
1、shmaddr为NULL,内核自动选择一个地址
2、不为NULL,如果shmflg设置了SHM_RND标记,那么连接的地址会自动向下调整为SHMLBA的整数倍(shmaddr-(shmaddr%SHMLBA);如果没有设置SHM_RND标记那么shmaddr就是连接的地址。
3、shmflg=SHM_RDONLY,表示连接操作用来只读共享内存


shmdt函数:将共享内存段与当前进程脱离

int shmdt(const void* shmaddr);
//shmaddr:是shmat返回的shmaddr
//返回值:失败返回-1,成功返回0
注意:
将共享内存与当前进程脱离并不意味着共享内存的释放。

shmctl函数:共享内存的控制函数

int shmctl(int shmid,int cmd,struct shmid_ds* uf);
//shmid:shmget函数获得的共享内存标识符
//cmd:将要采取的动作
//buf:指向一个保存着共享内存的模式状态和访问权限的数据结构
//成功返回0,失败返回-1

cmd解释:

命令 说明
IPC_STAT 把shmid结构中的数据设置为共享内存的当前关联值
IPC_SET 在进程有足够权限的前提下,把共享内存的当前关联值设置为shmid_ds数据结构中给出的值
IPC_RMID 删除共享内存段

模拟实现client-server通信

示例代码:
client.c文件:

#include"shmem.h"
#include<sys/shm.h>
int main(){
int shmid=OpenShm(4096);
sleep(1);
char* addr=shmat(shmid,NULL,0);
sleep(2);
int i=0;
while(i<20){
addr[i]='A'+i;
i++;
addr[i]=0;
sleep(1);
}
shmdt(addr);
sleep(2);
return 0;
}

server.c文件:

#include"shmem.h"

int main(){
int shmid=CreateShm(4096);
char* addr=shmat(shmid,NULL,0);
sleep(2);
int i=0;
while(i++<20){
printf("client say:%s\n",addr);
sleep(1);
}
shmdt(addr);
sleep(2);
DestroyShm(shmid);
return 0;
}

shmem.c文件:

#include"shmem.h"
static int commshm(int size,int flags){
key_t key=ftok(PATHNAME,PROJ_ID);
if(key<0){
perror("ftok\n");
return -1;
}
int shmid=0;
if(shmid=shmget(key,size,flags)<0){
perror("shmget\n");
return -1;
}
return shmid;
}

int CreateShm(int size){
return commshm(size,IPC_CREAT|IPC_EXCL|0666);
}
int OpenShm(int size){
return commshm(size,IPC_CREAT|IPC_EXCL|0666);
}


int DestroyShm(int shmid){
if(shmctl(shmid,IPC_RMID,NULL)<0){
perror("shmctl\n");
return -1;
}
}

shmem.h文件:

#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>


#define PATHNAME "."
#define PROJ_ID 0X6666

int CreateShm(int size);
int OpenShm(int size);
int DestroyShm(int shmid);

猜你喜欢

转载自blog.csdn.net/cx2479750196/article/details/80468808