2.28、共享内存(1)
2.28、内存共享(1)
- 1.共享内存是什么?
- 2.共享内存使用步骤
- ①shmget创建函数
- ②shmat关联内存函数
- ③可以直接对共享内存进行操作
- ④shmdt取消关联内存函数
- ⑤shmctl标记删除共享内存函数
- 3.共享内存操作函数
- 4.共享内存操作命令
- 5.共享内存操作函数详细介绍
- ①shmget
- ②shmat
- ③shmdt
- ④shmctl
- ⑤ftok
- 6.共享内存实际使用
- ①write_shm文件
- ②read_shm文件
1.共享内存是什么?
- 共享内存允许两个或者多个进程共享物理内存的同一块区域(通常被称为段)。由于一个共享内存段会称为一个进程用户空间的一部分,因此这种
IPC
机制无需内核介入。所有需要做的就是让一个进程将数据复制进共享内存中,并且这部分数据会对其他所有共享同一个段的进程可用。 - 与管道等要求发送进程将数据从用户空间的缓冲区复制进内核内存和接收进程将数据从内核内存复制进用户空间的缓冲区的做法相比,这种
IPC
技术的速度更快。
2.共享内存使用步骤
①shmget创建函数
- 调用
shmget()
创建一个新共享内存段或取得一个既有共享内存段的标识符(即由其他进程创建的共享内存段)。这个调用将返回后续调用中需要用到的共享内存标识符。
②shmat关联内存函数
- 使用
shmat()
来附上共享内存段,即使该段成为调用进程的虚拟内存的一部分。
③可以直接对共享内存进行操作
- 此刻在程序中可以像对待其他可用内存那样对待这个共享内存段。为引用这块共享内存,程序需要使用由
shmat()
调用返回的addr
值,它是一个指向进程的虚拟地址空间中该共享内存段的起点的指针。
④shmdt取消关联内存函数
- 调用
shmdt()
来分离共享内存段。在这个调用之后,进程就无法再引用这块共享内存了。这一步是可选的,并且在进程终止时会自动完成这一步。
⑤shmctl标记删除共享内存函数
需要这一块的共享内存连接数为0时才会删除,所以叫标记删除!
- 调用
shmctl()
来删除共享内存段。只有当当前所有附加内存段的进程都与之分离之后内存段才会销毁。只有一个进程需要执行这一步
3.共享内存操作函数
int shmget(key_t key, size_t size, int shmflg);
void *shmat(int shmid, const void *shmaddr, int shmflg);
int shmdt(const void *shmaddr);
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
key_t ftok(const char *pathname, int proj_id)
4.共享内存操作命令
ipcs
用法
ipcs -a
// 打印当前系统中所有的进程间通信方式的信息ipcs -m
// 打印出使用共享内存进行进程间通信的信息ipcs -q
// 打印出使用消息队列进行进程间通信的信息ipcs -s
// 打印出使用信号进行进程间通信的信息
ipcrm
用法ipcrm -M shmkey
// 移除用shmkey
创建的共享内存段ipcrm -m shmid
// 移除用shmid
标识的共享内存段ipcrm -Q msgkey
// 移除用msqkey
创建的消息队列ipcrm -q msqid
// 移除用msqid
标识的消息队列ipcrm -S semkey
// 移除用semkey
创建的信号ipcrm -s semid
// 移除用semid
标识的信号
5.共享内存操作函数详细介绍
①shmget
int shmget(key_t key, size_t size, int shmflg);
- 功能:创建一个新的共享内存段,或者获取一个既有的共享内存段的标识。
新创建的内存段中的数据都会被初始化为0
- 参数:
- key : key_t类型是一个整形,通过这个找到或者创建一个共享内存。
一般使用16进制表示,非0值
- size: 共享内存的大小
- shmflg: 属性
- 访问权限
- 附加属性:创建/判断共享内存是不是存在
- 创建:IPC_CREAT
- 判断共享内存是否存在: IPC_EXCL , 需要和IPC_CREAT一起使用
IPC_CREAT | IPC_EXCL | 0664
- 返回值:
失败:-1 并设置错误号
成功:>0 返回共享内存的引用的ID,后面操作共享内存都是通过这个值。
②shmat
void *shmat(int shmid, const void *shmaddr, int shmflg);
- 功能:和当前的进程进行关联
- 参数:
- shmid : 共享内存的标识(ID),由shmget返回值获取
- shmaddr: 申请的共享内存的起始地址,指定NULL,内核指定
- shmflg : 对共享内存的操作
- 读 : SHM_RDONLY, 必须要有读权限
- 读写: 0
- 返回值:
成功:返回共享内存的首(起始)地址。 失败(void *) -1
③shmdt
int shmdt(const void *shmaddr);
- 功能:解除当前进程和共享内存的关联
- 参数:
shmaddr:共享内存的首地址
- 返回值:成功 0, 失败 -1
④shmctl
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
- 功能:对共享内存进行操作。删除共享内存,共享内存要删除才会消失,创建共享内存的进行被销毁了对共享内存是没有任何影响。
- 参数:
- shmid: 共享内存的ID
- cmd : 要做的操作
- IPC_STAT : 获取共享内存的当前的状态
- IPC_SET : 设置共享内存的状态
- IPC_RMID: 标记共享内存被销毁
- buf:需要设置或者获取的共享内存的属性信息
- IPC_STAT : buf存储数据
- IPC_SET : buf中需要初始化数据,设置到内核中
- IPC_RMID : 没有用,NULL
⑤ftok
key_t ftok(const char *pathname, int proj_id);
- 功能:根据指定的路径名,和int值,生成一个共享内存的key
- 参数:
- pathname:指定一个存在的路径
/home/nowcoder/Linux/a.txt
/
- proj_id: int类型的值,但是这系统调用只会使用其中的1个字节
范围 : 0-255 一般指定一个字符 'a'
6.共享内存实际使用
①write_shm文件
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <string.h>
int main()
{
// 系统获取key值
key_t key = ftok("/home/nowcoder/Linux/lesson27/", 2);
printf("write_shm key: %d\n", key);
// 创建共享内存,返回值为shmid,为共享内存的唯一标识
int shmid = shmget(key, 1024, IPC_CREAT | 0664);
printf("write_shm shmid: %d\n", shmid);
// 关联内存,设置权限为读写
void* address = shmat(shmid, NULL, 0);
char* str = "hello world";
memcpy(address, str, strlen(str) + 1);
printf("按任意键继续\n");
getchar();
// 取消当前进程和共享内存的关联
shmdt(address);
// 删除共享内存
shmctl(shmid, IPC_RMID, NULL);
return 0;
}
②read_shm文件
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <string.h>
int main()
{
// 系统获取key值
key_t key = ftok("/home/nowcoder/Linux/lesson27/", 2);
printf("read_shm key: %d\n", key);
// 创建共享内存,返回值为shmid,为共享内存的唯一标识
int shmid = shmget(key, 1024, IPC_CREAT);
printf("read_shm shmid: %d\n", shmid);
// 关联内存,设置权限为读写
void* address = shmat(shmid, NULL, 0);
printf("%s\n", (char*) address);
printf("按任意键继续\n");
getchar();
// 取消当前进程和共享内存的关联
shmdt(address);
// 删除共享内存
shmctl(shmid, IPC_RMID, NULL);
return 0;
}