1.存储映射
存储映射I/O(Memory-mapped I/O)将一个磁盘文件和存储空间中的一个缓冲区映射。
使得用户可以直接在缓冲区读写数据,不必再去内存中读写。
1.1 mmap()
void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
函数功能:
- 建立映射
参数:
- addr:指定的开始映射的内存地址。一般使用NULL
- length:映射大小,单位字节
- prot:权限
PROT_READ 可读
PROT_WRITE 可写
- flags:
MAP_SHARED 共享的 -- 对映射区的修改会影响源文件
MAP_PRIVATE 私有的
- fd:文件描述符 需要打开一个文件
- offset :偏移量 ,从该位置开始映射,一般为0
1.2 munmap()
int munmap(void *addr, size_t length);
函数功能:
- 释放内存映射,仅对当前进程有效
参数:
- addr:映射区的首地址
- length:映射区的长度
1.3 truncate()
int truncate(const char *path, off_t length);
函数功能:
- 对打开的文件进行扩容
参数:
- path:要扩容的文件
- length:扩容的大小
案例:
添加映射:
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/mman.h>
int main(int argc, char const *argv[])
{
// 打开文件
int fd = open("/home/qf/桌面/week05/day03/temp", O_RDWR | O_CREAT, 0664);
if (fd < 0)
{
perror("open");
return 0;
}
// 扩容
int ret = truncate("/home/qf/桌面/week05/day03/temp",16);
// printf("ret=%d\n",ret);
//mmap映射
void * p=mmap(NULL,16,PROT_WRITE | PROT_READ,MAP_SHARED,fd,0);
//强转
char *buff=(char *)p;
//转换完就可以存入数据,那其他进程可以直接读走
return 0;
}
写:
strcpy(buff,"hello");
读:
printf("收到数据%s\n",buff);
2. 共享内存
共享内存允许两个或者多个进程共享给定的存储区域。
2.1 共享内存的特点
- 共享内存是进程间共享数据的一种最快的方法。
一个进程向共享的内存区域写入了数据,共享这个内存区域的所有进程就可以立刻看到其中的内容。
- 使用共享内存要注意的是多个进程之间对一个给定存储区访问的互斥。
若一个进程正在向共享内存区写数据,则在它做完这一步操作前,别的进程不应当去读、写这些数据。
2.2 API
2.2.1 shmget()
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size,int shmflg);
函数功能:
- 创建或打开一个共享内存区
参数:
- key:IPC键值
- size:共享内存段的大小
- shmflag:标识函数的行为以及共享内存的权限
IPC_CREAT:如果不存在就创建
IPC_EXCL:如果已经存在则返回失败
位或权限位:共享内存位或权限位后可以设置共享内存的访问权限,格式和 open 函数的 mode_t 一样,但可执行权限未使用。
返回值:
- 成功:返回共享内存的标识符
- 失败:-1
查看:
查看消息队列: ipcs -q
产看共享内存:ipcs -m
删除共享内存 ipcrm -m shmid
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/mman.h>
int main(int argc, char const *argv[])
{
key_t key =ftok("/home/qf/桌面/week05/day03",05);
// printf("key=%d\n",key);
//建立共享内存
int shmid =shmget(key,16,IPC_CREAT);
if (shmid<0)
{
perror("shmget");
return 0;
}
// printf("shmid=%d\n",shmid);
return 0;
}
2.2.2 shmat()
#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr,int shmflg);
函数功能:
- 映射,将真实的物理内存与进程中的虚拟内存地址关联起来
参数:
- shmid:共享内存标识符
- shamaddr:共享内存映射地址,推荐NULL
- shmflg:共享内存段的可读可写权限
0:可读可写
SHM_RDONLY:只读
SHM_RND:(shmaddr 非空时才有效)没有指定 SHM_RND 则此段连接到 shmaddr 所指定的地址上(shmaddr 必需页对齐)。指定了 SHM_RND 则此段连接到 shmaddr- shmaddr%SHMLBA 所表示的地址上。
返回值:
- 成功:返回共享内存段映射地址
- 失败:-1
2.2.3 shmdt()
#include <sys/types.h>
#include <sys/shm.h>
int shmdt(const void *shmaddr);
函数功能:
- 解除映射
参数:
- shamaddr:共享内存段映射地址
案例:
写:
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/mman.h>
int main(int argc, char const *argv[])
{
key_t key =ftok("/home/qf/桌面",05);
// printf("key=%d\n",key);
//建立共享内存
int shmid =shmget(key,4096,IPC_CREAT | 0666);
if (shmid<0)
{
perror("shmget");
return 0;
}
// printf("shmid=%d\n",shmid);
//建立映射
char *buff=(char *)shmat(shmid,NULL,0);
strcpy(buff,"hello");
//解除当前进程与共享内存的连接
shmdt(buff);
return 0;
}
读:
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/mman.h>
int main(int argc, char const *argv[])
{
key_t key =ftok("/home/qf/桌面",05);
// printf("key=%d\n",key);
//建立共享内存
int shmid =shmget(key,4096,IPC_CREAT | 0666);
if (shmid<0)
{
perror("shmget");
return 0;
}
// printf("shmid=%d\n",shmid);
//建立映射
char *buff=(char *)shmat(shmid,NULL,0);
printf("%s\n",buff);
//解除当前进程与共享内存的连接
shmdt(buff);
return 0;
}
2.2.4 共享内存控制函数
#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd,struct shmid_ds *buf);
函数功能:
- 共享内存空间的控制。
参数:
- shmid:共享内存标识符。
- cmd:函数功能的控制。
PC_RMID:删除。(常用)
IPC_SET:设置 shmid_ds 参数。
IPC_STAT:保存 shmid_ds 参数。
SHM_LOCK:锁定共享内存段(超级用户)。
SHM_UNLOCK:解锁共享内存段。
- buf:shmid_ds 数据类型的地址,用来存放或修改共享内存的属性。
返回值:
- 成功:0
- 失败: -1
SHM_LOCK 用于锁定内存,禁止内存交换。
并不代表共享内存被锁定后禁止其它进程访问。
其真正的意义是:被锁定的内存(物理内存)不允许被交换到虚拟内存中。
这样做的优势在于让共享内存一直处于内存中,从而提高程序性能