目录
●什么是共享内存?
两个或多个进程共享一段特定的存储区,这块存储区就叫做共享内存。进程可以将共享内存挂接到它们自己的进程地址空间中,这样一来,不同的进程就可以进行读取或修改共享内存中的数据,实现了进程间通信。
●共享内存的原理?
共享内存的原理如上图所示,主要分为两部(创内存、挂接):
1.进程在物理内存上开辟一块空间,这块空间称为共享内存。
2.不同进程将这块空间挂接到自己的进程地址空间中。
3.进程通过虚拟地址和页表的映射找到共享内存,然后对共享内存进行读写数据。
●共享内存的特点 ?
1.共享内存区是最快的IPC形式。一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据。
2.共享内存的生命周期随内核。
3.共享内存没有同步互斥机制,需要用户自己维护共享内存。
●共享内存的数据结构?
struct shmid_ds {
struct ipc_perm shm_perm; /* operation perms */
int shm_segsz; /* size of segment (bytes) */
__kernel_time_t shm_atime; /* last attach time */
__kernel_time_t shm_dtime; /* last detach time */
__kernel_time_t shm_ctime; /* last change time */
__kernel_ipc_pid_t shm_cpid; /* pid of creator */
__kernel_ipc_pid_t shm_lpid; /* pid of last operator */
unsigned short shm_nattch; /* no. of current attaches */
unsigned short shm_unused; /* compatibility */
void *shm_unused2; /* ditto - used by DIPC */
void *shm_unused3; /* unused */
};
shmge
●共享内存函数
1.创建共享内存shmget
功能:⽤来创建共享内存
原型
int shmget(key_t key, size_t size, int shmflg);
参数
key:这个共享内存段名字(和消息队列一样由ftok获取)
size:共享内存⼤⼩(自己指定,一般为页的整数倍)
shmflg:由九个权限标志构成,它们的⽤法和创建⽂件时使⽤的mode模式标志是⼀样的
IPC_CREAT:创建新的共享内存
IPC_CREAT|IPC_EXCL|0666:若创建的共享内存存在,报错
IPC_NOWAIT:非阻塞
0:如果是打开文件,写0
返回值:成功返回⼀个⾮负整数,即该共享内存段的标识码;失败返回-1
2.挂接共享内存shmat
功能:将共享内存段连接到进程地址空间
原型
void *shmat(int shmid, const void *shmaddr, int shmflg);
参数
shmid: 共享内存标识
shmaddr:指定连接的地址(一般默认为NULL,由系统自动分配内存)
shmflg:它的两个可能取值是SHM_RND和SHM_RDONLY(连接操作用于只读内存)
返回值:成功返回⼀个指针,指向共享内存第⼀个节;失败返回-1
3.脱离挂接shmdt
功能:将共享内存段与当前进程脱离
原型
int shmdt(const void *shmaddr);
参数
shmaddr: 由shmat所返回的指针
返回值:成功返回0;失败返回-1
注意:将共享内存段与当前进程脱离不等于删除共享内存段
4.共享内存控制shmctl
功能:⽤于控制共享内存
原型
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数
shmid:由shmget返回的共享内存标识码
cmd:将要采取的动作(有三个可取值)
buf:指向⼀个保存着共享内存的模式状态和访问权限的数据结构
返回值:成功返回0;失败返回-1
cmd取值:
5.查看/删除共享内存
//查看
ipcs -m
//删除
ipcrm -m id(标识)
●server/client实例
common.h:
#ifndef _COMM__H_
#define _COMM__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 destroyShm(int shmid);
int getShm(int size);
#endif
common.c
#include"common.h"
static int commShm(int size,int flags)
{
key_t _key=ftok(PATHNAME,PROJ_ID);
if(_key<0)
{
perror("ftok");
return -1;
}
int shmid=0;
if((shmid=shmget(_key,size,flags))<0)
{
perror("shmget");
return -2;
}
return shmid;
}
int destroyShm(int shmid)
{
if(shmctl(shmid,IPC_RMID,NULL)<0)
{
perror("shmctl");
return -1;
}
return 0;
}
int createShm(int size)
{
return commShm(size,IPC_CREAT|IPC_EXCL|0666);
}
int getShm(int size)
{
return commShm(size,IPC_CREAT);
}
sever.c
#include"common.h"
int main()
{
int shmid=createShm(4096);//创建共享内存
char* addr=shmat(shmid,NULL,0);//挂接
sleep(2);
int i=0;
while(i++<26)
{
printf("client say# %s\n",addr);
sleep(1);
}
shmdt(addr);//脱离
sleep(2);
destroyShm(shmid);
return 0;
}
client.c
#include"common.h"
int main()
{
int shmid=getShm(4096);//获取共享内存
sleep(1);
char* addr=shmat(shmid,NULL,0);
sleep(2);
int i=0;
while(i<26)
{
addr[i]='A'+i;
i++;
addr[i]=0;
sleep(1);
}
shmdt(addr);
sleep(2);
return 0;
}
结果演示: