共享内存
基于共享存储区的通信方式, 为了传输大量数据, 在内存中划出了一块共享存储区域, 通信的进程都可以对这块内存进行操
作, 通过对该内存的读或写交换信息, 实现通信, 这种通信属于高级通信, 通信的进程在通信前先向系统申请一块空间, 然后将
这块空间映射到自己的虚拟地址空间中, 使用完成后不再需要的话再将归还给系统
共享内存是所有进程间通信方式中最快的一种
那么为什么共享内存是最快的呢?
共享内存是将同一块物理内存映射到自己的虚拟地址空间中, 实现对相同的一块物理内存进行操作, 通过这种方式实现多
个进程间的数据共享功能, 少了两次用户态与内核间的数据拷贝过程, 所以最快.
注意:
1. 管道生命周期随内核
2. 共享内存是不受保护的, 多个进程同时操作的时候可能会造成混乱, 需要通过同步与互斥进行保护
操作步骤:
1. 创建共享内存 shmget()
2. 将共享内存映射到虚拟地址空间 shmat()
3. 对这块空间进行操作 memcpy
4. 不使用了就解除映射关系 shmdt()
5. 删除共享内存 shmctl()
共享内存函数
1. 创建共享内存(在内存中创建一块共享内存)
int shmget(key_t key, size_t size, int shmflg); 参数: key : 共享内存标识符 可以使用define宏定义, 也可以使用ftok函数进行生成, 但是一般推荐使用define更好一点 size : 共享内存大小 shmflg: 选项标志 IPC_CREAT 共享内存不存在则创建, 存在则打开 IPC_EXCL 与IPC_CREAT同用, 共享内存存在则报错 shm_mode 权限 返回值: 标识符(代码中的操作句柄) 失败:-1
注意: shmflg是权限标志构成, 对权限不清楚的可以参考Linux---权限, 先了解了解权限
2. 建立映射(将共享内存与当前进程绑定在一起, 将共享内存段连接到进程地址空间)
void *shmat(int shmid, const void *shmaddr, int shmflg); 参数 shmid : 标识符 shmaddr: 置空-映射首地址由操作系统分配 shmflg : 映射成功后的操作权限 SHM_RDONLY 只读 0 默认-可读可写 返回值: 映射首地址 失败返回:-1
3. 解除映射(将共享内存与当前进程脱离)
int shmdt(const void *shmaddr); shmaddr: 映射首地址 返回值: 成功:0 失败:-1
注意: 脱离不等于删除, 就相当于你的QQ号码和你的微信号关联了, 现在你不想要这个QQ号码了, 现在先解除关联, 但是你的QQ号码并没有消失, 你还得注销这个QQ号码
4. 控制共享内存(可以删除共享内存)
int shmctl(int shmid, int cmd, struct shmid_ds *buf); shmid: 操作句柄 cmd : 操作类型 IPC_RMID 删除共享内存 IPC_STAT 把shmid_ds结构中的数据设置为共享内存的当前关联值 IPC_SET 在进程中有权限的前提下, 把共享内存的当前关联设置为shmid_ds中给出的值 buf : 设置/获取共享内存信息 共享内存不会被直接删除, 而是判断当前映射连接数是否为0 为0: 直接删除 不为0: 拒绝后续其它进程的映射连接, 当映射连接数为0时自动删除
实现通信:
shm_write.c
#include <stdio.h> #include <errno.h> #include <unistd.h> #include <sys/shm.h> #define IPC_KEY 0x12345678 int main() { //1. 创建共享内存 int shmid = shmget(IPC_KEY, 32, IPC_CREAT | 0664); if(shmid < 0) { perror("shmget error"); return -1; } //2. 建立映射 char* shm_start = shmat(shmid, NULL, 0); if(shm_start == (void*)-1) { perror("shmat error"); return -1; } //3.操作 int i = 0; while(1) { sprintf(shm_start, "这是一片博客---+%d\n",i++); sleep(1); } //4.解除映射 shmdt(shm_start); //5.删除共享内存 shmctl(shmid, IPC_RMID, NULL); return 0; }
shm_read.c
只在第三步操作时候做出了修改
//3.操作 int i = 0; while(1) { printf("%s", shm_start); sleep(1); }
运行: