linux_共享存储映射区-mmap函数-munmap函数-进程通信-strace命令
接上一篇:linux_FIFO命名管道-mkfifo函数-进程通信
今天来分享linux的共享映射区,主要就是mmap函数和munmap函数的使用,话不多说,上菜:
目录
- 1.共享存储映射I/O
- 2.mmap函数
- 3.munmap函数
- 4.例子:模拟malloc函数实现
- 5.例子:使用文件创建映射区
- 7.例子:创建匿名映射区
- 8.strace命令使用
1.共享存储映射I/O
共享存储映射I/O就是使一个磁盘文件与存储空间中的一个缓冲区相映射,当从缓冲区中取数据,就相当于读文件中的相应字节;将数据存入缓冲区,则相应的字节就自动写入文件。
使用这种方法,就需要用到两个函数,mmap和munmap函数。
2.mmap函数
函数作用:
创建的映射区首地址。
头文件:
#include <sys/mman.h>
函数原型:
void *mmap(void *adrr, size_t length, int prot, int flags, int fd, off_t offset);
函数参数:
addr: 建立映射区的首地址,由Linux内核指定。使用时,直接传递NULL
length: 欲创建映射区的大小
prot: 映射区权限PROT_READ、PROT_WRITE、PROT_READ|PROT_WRITE
flags: 标志位参数(常用于设定更新物理区域、设置共享、创建匿名映射区)MAP_SHARED: 会将映射区所做的操作反映到物理设备(磁盘)上。MAP_PRIVATE: 映射区所做的修改不会反映到物理设备。
fd: 用来建立映射区的文件描述符
offset:映射文件的偏移(4k的整数倍)为什么是4k的整数倍,因为mmu创建的映射区,mmu的最小单位是4k
返回值:
成功:返回创建的映射区首地址;
失败:返回MAP_FAILED宏
3.munmap函数
函数作用:
删除指定地址范围的映射。
头文件:
#include <sys/mman.h>
函数原型:
int munmap(void *addr, size_t length);
函数参数:
addr:映射区首地址
length:映射区大小
返回值:
成功:0;
失败:-1
注意:
①当进程终止时,区域也会自动取消映射;
②若fd存在,手动关闭文件描述符不会取消映射该区域。
4.例子:模拟malloc函数实现
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>void *Malloc(size_t size)
{void *p = NULL;p = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);//MAP_ANONYMOUS必须加上,或加上MAP_ANONif (p == MAP_FAILED) { p = NULL;perror("mmap failed");exit(1);}return p;
}void Free(void *ptr, size_t size)
{munmap(ptr, size);//删除分配的映射区
}
int main(void)
{int *p = NULL;pid_t pid;p = (int *)Malloc(40);pid = fork(); //创建子进程if (pid == 0) {p[0] = 2000;p[1] = 3000;printf("子进程: p[0] = %d p[1] = %d\\n", *p,p[1]);} else {sleep(1);printf("父进程: p[0] = %d p[1] = %d\\n", *p,p[1]);}Free(p, 4);return 0;
}
5.例子:使用文件创建映射区
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/mman.h>int main(void)
{char *pbuf = NULL;int fd = open("hello", O_RDWR|O_CREAT|O_TRUNC, 0644);//读写、文件不存在则创建,文件存在则截断if (fd < 0){perror("open error");exit(1);}ftruncate(fd, 20);//文件拓展20个字节pbuf = mmap(NULL, 20, PROT_WRITE, MAP_SHARED, fd, 0);if (pbuf == MAP_FAILED){perror("map error");exit(1);}close(fd);strcpy(pbuf, "hello friend!");//复制字符串到pbuf中printf("%s\\n", pbuf);if (munmap(pbuf, 4) < 0){perror("munmap error");exit(1);}return 0;
}
6.例子:使用映射区进行父子进程通信
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/wait.h>
int var = 15;
int main(void)
{int *p = NULL;pid_t pid;int fd;fd = open("hello", O_RDWR|O_CREAT|O_TRUNC, 0644);//读写、文件不存在则创建,文件存在则截断if(fd < 0){perror("open error");exit(1);}unlink("hello"); //删除临时文件目录项,使之具备被释放条件.ftruncate(fd, 4);//p = (int *)mmap(NULL, 4, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);p = (int *)mmap(NULL, 4, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);//MAP_SHARED父子进程共享映射区if(p == MAP_FAILED){ //注意:不是p == NULLperror("mmap error");exit(1);}close(fd); //映射区建立完毕,即可关闭文件pid = fork(); //创建子进程if(pid == 0){*p = 2000;var = 188;printf("子进程: *p = %d, var = %d\\n", *p, var);} else {sleep(1);printf("父进程: *p = %d, var = %d\\n", *p, var);wait(NULL);int ret = munmap(p, 4); //释放映射区if (ret == -1) {perror("munmap error");exit(1);}}return 0;
}
7.例子:创建匿名映射区
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
int main(void)
{int *p;pid_t pid;p = mmap(NULL, 4, PROT_READ|PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); //MAP_ANONYMOUS必须加上,或加上MAP_ANON,虽然可能找不到该宏if(p == MAP_FAILED){ //注意:不是p == NULLperror("mmap error");exit(1);}pid = fork(); //创建子进程if(pid == 0){*p = 2000;printf("子进程:*p = %d\\n", *p);} else {sleep(1);printf("父进程:*p = %d\\n", *p);}munmap(p, 4); //释放映射区return 0;
}
8.strace命令使用
strace +可执行文件 #可以追踪该程序调用哪些函数
例如:
strace ./test1
#追踪test1可执行文件调用了哪些函数
以上就是本次的分享了,希望能对大家有所帮助。
此博主在CSDN发布的文章目录:【我的CSDN目录,作为博主在CSDN上发布的文章类型导读】