alin的学习之路:共享内存Linux下的API

共享内存是进程间通信中最简单的方式之一。共享内存允许两个或更多进程访问同一块内存,当一个进程改变了这块地址中的内容的时候,其它进程都会察觉到这个更改。

  1. 共享内存使用流程
1. 向内核申请一块内存 -> 指定大小
2. 如果有两个进程, 需要通信, 可以使用这块共享内存来完成, 先创建出这两个进程
	- 进程A
	- 进程B
3. 进程A和进程B分别和共享内存进行关联
	- 拿到共享内存的地址 -> 首地址
4. 两个进程可以通过这个首地址对共享内存进行读/写操作
5. 如果这个进程不再使用这块共享内存, 需要和共享内存断开关联
	- 进程退出, 对共享内存是没有任何影响的
6. 当不再使用共享内存的时候, 需要将共享内存销毁
  1. 共享内存头文件
#include <sys/ipc.h>
#include <sys/shm.h>
  1. 共享内存操作函数
  • 创建或打开一块共享内存区
// 创建共享内存
// 共享内存已经存在, 打开共享内存
// 可以创建多块共享内存
int shmget(key_t key, size_t size, int shmflg);
	参数:
		- key: 通过这个key记录共享内存在内核中的位置, 需要是一个>0的整数, ==0不行
			随便指定一个数就可以, 后边会介绍一个函数ftok
		- size: 创建共享内存的时候, 指定共享内存的大小
			- 如果是打开一个已经存在的共享内存, size写0就可以
		- shmflg: 创建共享内存的时候使用, 类似于open函数的flag
			- IPC_CREAT: 创建共享内存
				- 创建的时候需要给共享内存一个操作权限
					- IPC_CREAT | 0664
			- IPC_CREAT | IPC_EXCL: 检测共享内存是否存在
				- 如果存在函数返回-1
                - 不存在, 返回0
	返回值:
		成功: 创建/打开成功, 得到一个整形数 -> 对应这块共享内存
		失败: -1
// 应用
// 1. 创建共享内存
int shmid = shmget(100, 4096,  IPC_CREAT | 0664);
int shmid = shmget(200, 4096,  IPC_CREAT | 0664);
// 2. 打开共享内存
int shmid = shmget(100, 0, 0);
  • 将当前进程和共享内存关联到一起
// 进程和共享内存产生关系
void *shmat(int shmid, const void *shmaddr, int shmflg);
	参数:
		- shmid: 通过这个参数访问共享内存, shmget()函数的返回值
		- shmaddr: 指定共享内存在内核中的位置, 写NULL -> 委托内核区指定
		- shmflg: 关联成功之后对共享内存的操作权限
			- SHM_RDONLY: 只读
			- 0: 读写
	返回值:
		成功: 共享内存的地址 (起始地址)
        失败:  (void *) -1
// 函数调用:
void* ptr = shmat(shmid, NULL, 0);
// 写内存
memcpy(ptr, "xxxx", len);
// 读内存
printf("%s", (char*)prt);
  • 将共享内存和当前进程分离
// 进程和共享内存分离 -> 二者就没有关系了
int shmdt(const void *shmaddr);
	参数: 共享内存的起始地址, shmat()返回值
	返回值:
		- 成功: 0
        - 失败: -1
  • 共享内存操作 -( 删除共享内存 )
// fcntl
// setsockopt
// getsockopt
// 对共享内存进程操作
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
	参数: 
		- shmid: 通过这个参数访问共享内存, shmget()函数的返回值
		- cmd: 对共享内存的操作
			- IPC_STAT: 获取共享内存的状态
			- IPC_SET: 设置共享内存状态
			- IPC_RMID: 标记共享内存要被销毁
		- buf: 为第二个参数服务的
			cmd==IPC_STAT: 获取共享内存具体状态信息
			cmd==IPC_SET: 自定义共享内存状态, 设置到内核的共享内存中
			cmd==IPC_RMID: 这个参数没有用了, 指定为NULL
	返回值:
		成功: 0
        失败: -1
// 删除共享内存
shmctl(shmid, IPC_RMID, NULL);