System V IPC 机制 (msg/sem/shm)
System V引入了三种高级的进程间通信机制:
消息队列
共享内存
信号量
消息队列 共享内存 信号量
头文件 <sys/msg.h> <sys/shm.h> <sys/sem.h>
创建 msgget shmget semget
操作 msgctl shmctl semctl
...System V IPC原理:
就是在内核中,建立一个数据结构,提供一些操作数据结构的函数接口使用步骤:
1. 先向内核申请一个IPC key("许可证")
IPC对象通过“key”来引用和访问IPC对象,所有的system V的IPC对象在内核中都有一个唯一的标识ID,在用户空间我们称之为“key”
key:唯一的标识一个system V的IPC对象 (msg,sem,shm)
不同的进程利用相同的“key”可以访问同一个IPC对象
key:由用户提供的一个整数和一个字符串生成
2. 利用KEY创建或者打开IPC对象(msg,sem,shm)
不同的进程利用相同的“key”可以访问同一个IPC对象
msgget:创建或者打开system v 消息队列
shmget:创建或者打开system v 共享内存
semget:创建或者打开system v 消息队列
3. 读 / 写 / 操作三种IPC对象的操作方法都不一样
一. System V 共享内存
进程间通信常用的方法,多个进程共享一段内存“共享内存”
进程的地址空间是独立的 (共享的内存是存在于内核)
“随内核的持续性”
共享内存其实就是通过映射的方式使得多个进程可以同时访问同一块内存,换而言之就是将一块内存 同时映射到多个进程的进程地址空间中,借此这些进程就可以通过这块内存进行数据交流。这块内存就 称之为共享内存
由于是多个进程共享一段内存,这段内存既是你的,又是我的,p1往这段内存中写入数据,实际上就是写入p2的内存中。比管道少一次copy
共享内存的效率比管道高
实现方式:
在内核中开辟 (申请)一块共享内存,其他的进程通过“映射”方式获取这一段内存的引用(指针)
进程P1可以映射并且操作这一段内存,同时P2也可以映射并且操作这一段内存
使用方式:1. 申请一个system V IPC的key:ftok
所有的system V的IPC是相同的
ftokNAME ftok - convert a pathname and a project identifier to a System V IPC key SYNOPSIS #include <sys/types.h> #include <sys/ipc.h> ftok的英文可以理解为 file to key ftok利用一个文件名和一个项目ID(整数)生成一个key key_t ftok(const char *pathname, int proj_id); pathname:一个文件的路径名(必须存在) proj_id:一个指定的整数 如果两个进程要通过system V通信,那么他们的ftok的两个参数必须相同,这样才 可以产生同样的key,从而打开同一个IPC对象 返回值: 成功返回一个ipc的key,类型是key_t 失败返回-1,同时errno被设置 key_t key = ftok(PATHNAME, PROJID);
2. 创建或者打开system V共享内存对象:shmget
shmget (share memory)
NAME shmget - allocates a System V shared memory segment SYNOPSIS #include <sys/ipc.h> #include <sys/shm.h> shmget:用来在内核中创建或者打开一个system V的共享内存(IPC对象) int shmget(key_t key, size_t size, int shmflg); key:system V IPC对象的key,一般是ftok的返回值 size:以字节为单位指定共享内存区域的大小 在实际操作时,当shmget是创建一个新的共享内存区域时,必须指定一个不为0的size 值,一般是4096的整数倍,如果shmget是打开一个已经存在的共享内存区域时,size == 0 shmflg:标志位 a. 创建共享内存,如果底层已经存在,则获取并返回;如果不存在, 则创建共享内存然后再返回 IPC_CREAT | 权限位(同open函数) 如: IPC_CREAT | 0664(S_IRUSR...) b. 打开 0 返回值: 成功返回共享内存区域的id(标识打开的共享内存对象),这个id就标识唯一的共享内存 失败返回-1,同时errno被设置 创建创建共享内存,如果底层已经存在,则获取并返回;如果不存在,则创建共享内存然后再返回 int shm_id = shmget(key, SIZE, IPC_CREAT | 0664); 打开 int shm_id = shmget(key, 0, 0);
3. 映射 (shmat) / 解映射 (shmdt)