Shm 内存共享

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);```

### 5ftok() --- 用路径达到 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 的区别:

  1. shm可以直接创建, mmap 创建依赖磁盘文件mmap匿名映射,不能在无血缘关系进程间通信
  2. shm效率更高
    • shm直接对内存操作
    • mmap需同步磁盘文件
  3. 内存的共享
    • shm:所有关联进程操作同一块内存
    • mmap:
      • 每个进程都在自己的虚拟地址空间有一块独立内存
  4. 数据安全性
    • 进程异常终止
      • shm还在
      • mmap消失
    • 死机
      • shm中数据 -> 消失
      • mmap中数据 -> 消失
        • mmap关联磁盘文件, 二者同步-> 还在
  5. 生命周期
    • 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标识的信号```

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值