共享内存本质让不同进程看到同一份资源。
申请共享内存:
1、操作系统在物理内存当中申请一块内存空间
2、将申请好的内存分别挂接到各自进程的进程地址空间上
具体如何挂接:
将这块内存空间经过各自进程的页表映射到进程地址空间的共享区中,给应用层返回共享内存的起始虚拟地址
从而实现了进程A和进程B通过各自的页表访问同一块物理内存
当前进程如何释放共享内存:
1、把当前进程与共享内存去掉关联,把页表的映射关系去掉
2、释放共享内存
申请共享内存、挂接、去掉关联、释放共享内存这些操作都不是进程直接操作的,是由操作系统来完成
在系统当中可能会有大量的进程在进行通信,因此系统当中就可能存在大量的共享内存,那么操作系统必然要对其进行管理,所以共享内存除了在内存当中真正开辟空间之外,系统一定还要为共享内存维护相关的内核数据结构
共享内存的数据结构:
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 */
};
struct ipc_perm{
__kernel_key_t key;
__kernel_uid_t uid;
__kernel_gid_t gid;
__kernel_uid_t cuid;
__kernel_gid_t cgid;
__kernel_mode_t mode;
unsigned short seq;
};
key:
1、必须在内核中具有唯一性,能够让不同的进程进行唯一性标识
2、第一个进程可以通过key创建共享内存,第二个之后的进程,只要拿着同一个key就可以和第一个进程看到同一个共享内存了
3、对于一个已经创建好的共享内存,key在哪 ?
key在共享内存的描述对象中
传入shmget函数的第一个参数key,需要我们使用ftok函数进行获取
size:
表示待创建共享内存的大小。
shmflg:
表示创建共享内存的方式
1、IPC_CREAT(单独使用):
如果内核中不存在键值与key相等的共享内存,则新建一个共享内存并返回该共享内存的句柄;如果存在这样的共享内存,则直接返回该共享内存的句柄
句柄:我们把具有标定某种资源能力的东西叫做句柄,而这里shmget函数的返回值实际上就是共享内存的句柄,这个句柄可以在用户层标识共享内存,当共享内存被创建后,我们在后续使用共享内存的相关接口时,都是需要通过这个句柄对指定共享内存进行各种操作
2、IPC_CREAT | IPC_EXCL:
如果内核中不存在键值与key相等的共享内存,则新建一个共享内存并返回该共享内存的句柄;如果存在这样的共享内存,则出错返回
IPC_EXCL:不单独使用!
ftok函数的作用就是,将一个已存在的路径名pathname和一个整数标识符proj_id转换成一个key值,称为IPC键值,在使用shmget函数获取共享内存时,这个key值会被填充进维护共享内存的数据结构当中。需要注意的是,pathname所指定的文件必须存在且可存取
使用ftok函数生成key值可能会产生冲突,此时可以对传入ftok函数的参数进行修改。
需要进行通信的各个进程,在使用ftok函数获取key值时,都需要采用同样的路径名和和整数标识符,进而生成同一种key值,然后才能找到同一个共享资源
ipcs -q 列出消息队列相关信息
[cxq@iZ7xviiy0goapxtblgih6oZ 1. sharemem]$ ipcs -q
------ Message Queues --------
key msqid owner perms used-bytes messages
显示系统中正在使用的System V共享内存段的信息
[cxq@iZ7xviiy0goapxtblgih6oZ 1. sharemem]$ ipcs -m
共享内存的生命周期是随内核的,内核存在,共享内存就存在
用户不主动关闭,共享内存会一直存在
如果想要关闭共享内存,只能内核重启(用户释放)
关闭共享内存:
0是shmid
[cxq@iZ7xviiy0goapxtblgih6oZ 1. sharemem]$ ipcrm -m 0
让当前进程和指定的共享内存关联起来
第一个参数shmid,表示所控制共享内存的用户级标识符。
第二个参数cmd,表示具体的控制动作。
shmctl函数的第二个参数传入的常用的选项有以下三个
1、IPC_STAT,获取共享内存的当前关联值,此时参数buf作为输出型参数
2、IPC_SET ,在进程有足够权限的前提下,将共享内存的当前关联值设置为buf所指的数据结构中的值
3、IPC_RMID ,删除共享内存段
第三个参数buf,用于获取或设置所控制共享内存的数据结构
管道通信:
将一个文件从一个进程传输到另一个进程需要进行四次拷贝操作
1、server将信息从输入文件复制到server的临时缓冲区中。
2、将server临时缓冲区的信息复制到管道中。
3、client将信息从管道复制到client的缓冲区中。
4、将client临时缓冲区的信息复制到输出文件中。
使用共享内存进行通信,将一个文件从client传输到server只需要进行两次拷贝操作
1、从输入文件到共享内存。
2、从共享内存到输出文件。
优:共享内存是所有进程间通信方式中最快的一种通信方式,因为该通信方式需要进行的拷贝次数最少
缺:管道是自带同步与互斥机制的,但是共享内存并没有提供任何的保护机制,包括同步与互斥。