1:数据内存共享主要作用
- 共享内存是进程间通信中最简单的方式之一
- 允许两个或更多进程访问同一块内存
2:进程间通信实现内存共享步骤:
- 创建进程(会使用共享内) shmget()函数
- 创建共享内存shm,指定共享内存的大小 <shm: 内核的一块空间大小>
- 使用共享内存的进程,与shm建立关联关系。 shmat() 函数
注意:使用同一块内存的进程要建立关联关系, shmat() 返回值:为共享内存的首地址 - 进程间,使用 shm 进行数据通信
常用数据函数:write(), read(), mem-家族, str-家族 - 数据传递结束,进程断开与shm的关联。 shmdt() 函数
- 当所有进程使用结束时,最后一个进程负责释放shm. shmctl() 函数
3:shm 常用函数介绍
1 :shmget()函数: 创建或打开共享内存
int shmget(key_t key, size_t size, int shmflg);
参数:
key:共享内存,在内核中的标识符。
传 >0 数。 不能传 0。—— 0,代表shm被标记为“可删除”。
size:要创建的共享内存大小。单位:字节。
打开时,传0
shmflg: —— 参考 open
- IPC_CREAT: 创建共享内存。
- IPC_CREAT|0644:创建的同时,指定权限。
- IPC_CREAT|IPC_EXCL: 判断共享内存是否存在。
存在:-1
不存在:0
打开时,传 0
返回值:
成功:非0标识符。int 正整数
失败:-1
// 举例:
// 创建共享内存:int shmid1 = shmget(100, 4096, IPC_CREAT|0644);
// int shmid2 = shmget(200, 4096, IPC_CREAT|0644);
// 打开共享内存:int shmid = shmget(100, 0, 0); ```
### 2:shmat() -- 关联共享内存:
```c
// 调用该函数的进程,会与指定的 共享内存建立关联关系
void *shmat(int shmid, const void *shmaddr, int shmflg);
参数:
shmid:shmget() 函数的返回值。用来标识共享内存。
shmaddr:共享内存内核地址。传:NULL 让内核自动分配。
shmflg:
- SHM_RDONLY:只读。
- 0:读写。
返回值:
成功:共享内存首地址
失败:(void *) -1
// 举例
// string *p = shmat(shmid, NULL, 0);
// memcpy(p, "hello", strlen("hello")); // 写```
### 3: shmdt() ---- 断开共享内存
```c
int shmdt(const void *shmaddr);
参数:shmat 返回值。
返回:成功:0.失败:-1,errno
// 举例
// shmdt(p); // p不能在使用过程中 修改。p++```
### 4: shmctl() --- 共享内存操作(删除共享内存)
```c
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数:
shmid:shmget() 函数的返回值。用来标识共享内存。
cmd:
- IPC_STAT:获取shm的状态信息。—— struct shmid_ds 结构体。
- IPC_SET: 设置shm的状态信息。
- IPC_RMID: 【标记】,当前共享内存,可以被删除。
- shm的关联进程个数为 0 时,内核负责销毁。
buf:
— 参2 为IPC_STAT时,传出 struct shmid_ds 结构体。
— 参2 为 IPC_SET时,传入 struct shmid_ds 结构体。
- 参2 为IPC_RMID时,NULL。
返回:成功:0.失败:-1,errno
// shmctl(shmid, IPC_RMID, NULL);```
### 5:ftok() --- 用路径达到 key 值
```c
key_t ftok(const char *pathname, int proj_id);
- 参数pathname: 对应某个存在的路径名或文件名 - 绝对路径
- /
- /home/itcast/a/b/c
- /usr/local/lib
- /home/itcast/a.txt
- 参数proj_id: 整型数,目前该函数实现只使用该变量占用内存的一部分(1个字节)
- 取值范围: 0-255
- 返回值:shmget函数所需的第一个参数。
key_t t = ftok("/home/", 'a');
shmget(t, 0, 0);```
# 4: 共享内存中常见问题
### 1:用函数查询一块共享内存中的关联进程个数
指定 shmctl 第2个参数为 IPC_STAT, 参3 传出共享内存的状态
传出的 struct shmid_ds 结构体 中,包含 关联共享内存的 个数
### 2:共享内存是否可以删除多次
可以!但是!只有第一个调用 shmctl的进程。成功返回。—— 标记成功
### 3:共享内存的 key 值为零待表的含义
当 shm 被标记删除。尚未被删除(其他进程占用当前shm)
key值为0的shm,不能再被新的进程 关联。已经关联的进程,可以继续通信。
# 5:shm 和 mmap 的区别:
- shm可以直接创建, mmap 创建依赖磁盘文件mmap匿名映射,不能在无血缘关系进程间通信
- shm效率更高
- shm直接对内存操作
- mmap需同步磁盘文件
- 内存的共享
- shm:所有关联进程操作同一块内存
- mmap:
- 每个进程都在自己的虚拟地址空间有一块独立内存
- 数据安全性
- 进程异常终止
- shm还在
- mmap消失
- 死机
- shm中数据 -> 消失
- mmap中数据 -> 消失
- mmap关联磁盘文件, 二者同步-> 还在
- 进程异常终止
- 生命周期
- mmap: 进程退出, 内存映射区销毁
- shm: 进程退出, 共享内存还在。手动删除、关机```
6: 共享内存的操作命令
1:ipcs 命令
ipcs -a // 打印当前系统中所有的进程间通信方式的信息
ipcs -m // 打印出使用共享内存进行进程间通信的信息 == 常用
================ 以下为了解内容 ================
ipcs -q // 打印出使用消息队列进行进程间通信的信息
ipcs -s // 打印出使用信号量进行进程间通信的信息```
### 2:ipcrm 命令
shmkey == shmget()的第一个参数
ipcrm -M shmkey // 移除用shmkey创建的共享内存段
shmid == shmget()的返回值
ipcrm -m shmid // 移除用shmid标识的共享内存段
================ 以下为了解内容 ================
ipcrm -Q msgkey // 移除用msqkey创建的消息队列
ipcrm -q msqid // 移除用msqid标识的消息队列
ipcrm -S semkey // 移除用semkey创建的信号
ipcrm -s semid // 移除用semid标识的信号```