接上一篇:linux_FIFO命名管道-mkfifo函数-进程通信
今天来分享linux的共享映射区,主要就是mmap函数和munmap函数的使用,话不多说,上菜:
共享存储映射I/O就是使一个磁盘文件与存储空间中的一个缓冲区相映射,当从缓冲区中取数据,就相当于读文件中的相应字节;将数据存入缓冲区,则相应的字节就自动写入文件。
使用这种方法,就需要用到两个函数,mmap和munmap函数。
函数作用:
创建的映射区首地址。
头文件:
#include
函数原型:
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宏
函数作用:
删除指定地址范围的映射。
头文件:
#include
函数原型:
int munmap(void *addr, size_t length);
函数参数:
addr:映射区首地址
length:映射区大小
返回值:
成功:0;
失败:-1
注意:
①当进程终止时,区域也会自动取消映射;
②若fd存在,手动关闭文件描述符不会取消映射该区域。
#include
#include
#include
#include
#include
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_ANON
if (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;
}
#include
#include
#include
#include
#include
#include
#include
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
#include
#include
#include
#include
#include
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 == NULL
perror("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;
}
#include
#include
#include
#include
#include
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 == NULL
perror("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;
}
strace +可执行文件 #可以追踪该程序调用哪些函数
例如:
strace ./test1
#追踪test1可执行文件调用了哪些函数
以上就是本次的分享了,希望能对大家有所帮助。
此博主在CSDN发布的文章目录:【我的CSDN目录,作为博主在CSDN上发布的文章类型导读】