Linux进程通信之mmap
mmap()函数:
void *mmap(void* addr,size_t length,int port,int flags,int fd,off_t offset);
返回:成功:返回创建的映射区首地址;失败:MAP_FAILED 宏
参数:
addr: 建立映射区的首地址,由linux内核决定。使用时直接传递NULL;
length: 欲创建映射区的大小
port: 映射区权限PROT _READ、PROT_WRITE 、PROT _READ|PROTWRITE
flags: 标志位参数(常用于设定更新物理区域、设置共享、创建匿名映射区)
MAP_SHARED: 会将映射区所做的操作反射到物理设备上
MAP_PRIVATE: 映射区所作的修改不会反映到物理设备。
fd: 用来建立映射区的文件描述符
offset: 映射文件的偏移(4K的整数倍)
/***
mmap.c
***/
#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<sys/mman.h> int main()
{
int len,ret;
char *p = NULL;
int fd = open("mytest.txt",O_CREAT|O_RDWR,);
if(fd < )
{
perror("open error:");
exit();
}
len = ftruncate(fd,);
if(- == len)
{
perror("ftruncate error:");
exit();
}
p = mmap(NULL,,PROT_READ|PROT_WRITE,MAP_SHARED,fd,);
if(p == MAP_FAILED)
{
perror("mmap error:");
exit();
}
strcpy(p,"abc"); ret = munmap(p,);
if(- == ret)
{
perror("mmap error:");
exit();
}
close(fd);
return ;
}
运行结果:
ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ gcc mmap.c -o mmap
ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ ./mmap
ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ cat mytest.txt
abc
mmap在使用过程中注意以下事项:
- 创建映射区的过程中,隐含着一次对映射文件的读操作。
- 当MAP_SHARED时,要求:映射区的权限 <= 文件打开的权限(出于对映射区的保护)。而MAP_PRIVATE则无所谓,因为mmap中的权限时对内存的限制。
- 映射区的释放和文件关闭无关。只要映射成功,文件可以立刻关闭。
- 特别注意:当映射文件大小为0时,不能创建映射区。所以:用于映射的文件必须有实际大小。mmap使用时常常会出现总线错误,通常是因为共享文件存储空间大小所引起的。
- munmap传入的地址一定是mmap的返回地址,坚决杜绝指针++操作
- 如果使用文件偏移,则值必须是4K的整数倍
- mmap创建映射区出错概率极高,一定要检查返回值,确保映射区建立成功再进行后续操作。
mmap父子进程间通信:
文件inode属性
struct stat
{
存储指针地址;
大小;
权限;
类型;
所以者;
}
/***
mmap_fork.c
***/
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/mman.h>
#include<sys/wait.h> int var = ; int main()
{
int *p;
pid_t pid; int fd;
fd = open("temp",O_RDWR|O_CREAT|O_TRUNC,);
if(fd < )
{
perror("open error");
exit();
}
unlink("temp");
ftruncate(fd,); p = (int*)mmap(NULL,,PROT_READ|PROT_WRITE,MAP_SHARED,fd,);
if(p == MAP_FAILED)
{
perror("mmap error");
exit();
}
close(fd); pid = fork();
if( == pid)
{
*p = ;
var = ;
printf("child, *p = %d, var = %d\n",*p,var);
}
else
{
sleep();
printf("parent, *p = %d, var = %d\n",*p,var);
wait(NULL); int ret = munmap(p,);
if(- == ret)
{
perror("munmap error");
exit();
}
}
return ;
}
运行结果:
ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ gcc mmap_fork.c -o mmap_fork
ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ ./mmap_fork
child, *p = 2000, var = 1000
parent, *p = 2000, var = 100
mmap创建匿名映射区
/***
fork_mmap_linux.c
***/
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/mman.h>
#include<sys/wait.h> int var = ; int main()
{
int *p;
pid_t pid; p = (int*)mmap(NULL,,PROT_READ|PROT_WRITE,MAP_SHARED | MAP_ANON,-,);
if(p == MAP_FAILED)
{
perror("mmap error");
exit();
} pid = fork();
if( == pid)
{
var = ;
*p = ;
printf("child, *p = %d,var = %d\n",*p,var);
}
else
{
sleep();
// printf("parent,*p = %d\n",*p);
printf("child, *p = %d,var = %d\n",*p,var);
wait(NULL);
int ret = munmap(p,);
if(- == ret)
{
perror("munmap error");
exit();
}
}
return ;
}
运行结果:
ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ gcc fork_map_linux.c -o fork_map_linux
ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ ./fork_map_linux
child, *p = 2000,var = 1000
child, *p = 2000,var = 100
注意:MAP_ANONYMOUS和MAP_ANON 这两个宏是linux操作系统特有的宏,再类Unix系统中如无该宏的定义,可以使用以下步骤来完成匿名映射区的建立。
- fd = open(“/dev/zero”,O_RDWR);
- p = mmap(NULL,size,PROT_READ|PROT_WRITE,MMAP_SHARED,fd,0);
/***
fork_map_anon.c
***/
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/mman.h>
#include<sys/wait.h> int var = ; int main()
{
int *p;
pid_t pid;
int fd = open("/dev/zero",O_RDWR); p = (int*)mmap(NULL,,PROT_READ|PROT_WRITE,MAP_SHARED,fd,);
if(p == MAP_FAILED)
{
perror("mmap error");
exit();
} pid = fork();
if( == pid)
{
var = ;
*p = ;
printf("child, *p = %d,var = %d\n",*p,var);
}
else
{
sleep();
// printf("parent,*p = %d\n",*p);
printf("child, *p = %d,var = %d\n",*p,var);
wait(NULL);
int ret = munmap(p,);
if(- == ret)
{
perror("munmap error");
exit();
}
}
return ;
}
运行结果:
buntu1604@ubuntu:~/wangqinghe/linux/20190807$ gcc fork_map.c -o fork_map
ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ ./fork_map
child, *p = 2000,var = 1000
child, *p = 2000,var = 100
mmap无血缘关系进程间通信:
/***
mmap_w.c
***/
#include<stdio.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/mman.h>
#include<string.h> struct STU
{
int id;
char name[];
char sex;
}; void sys_err(char *str)
{
perror(str);
exit();
} int main(int argc,char ** argv)
{
int fd;
struct STU student = {,"xiaoming",'m'};
char *mm; if(argc < )
{
printf("./a.out file_shared\n");
exit(-);
} fd = open(argv[],O_RDWR | O_CREAT,);
ftruncate(fd,sizeof(student)); mm = mmap(NULL,sizeof(student),PROT_READ|PROT_WRITE,MAP_SHARED,fd,);
if(mm == MAP_FAILED)
{
sys_err("mmap error");
} close(fd); while()
{
memcpy(mm,&student,sizeof(student));
student.id++;
sleep();
} munmap(mm,sizeof(student));
return ;
}
/***
mmap_r.c
***/
#include<stdio.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/mman.h>
#include<string.h> struct STU
{
int id;
char name[];
char sex;
}; void sys_err(char *str)
{
perror(str);
exit();
} int main(int argc,char ** argv)
{
int fd;
struct STU student;
struct STU *mm; if(argc < )
{
printf("./a.out file_shared\n");
exit(-);
} fd = open(argv[],O_RDONLY);
if(- == fd)
sys_err("open error"); mm = mmap(NULL,sizeof(student),PROT_READ,MAP_SHARED,fd,);
if(mm == MAP_FAILED)
{
sys_err("mmap error");
} close(fd); while()
{
printf("id=%d,name = %s,%c\n",mm->id,mm->name,mm->sex);
sleep();
} munmap(mm,sizeof(student));
return ;
}
Linux进程通信之mmap的更多相关文章
- linux 进程通信之 mmap
一,管道PIPE 二,FIFO通信 三,mmap通信 创建内存映射区. #include <sys/mman.h> void *mmap(void *addr, size_t length ...
- Linux进程通信----匿名管道
Linux进程通信中最为简单的方式是匿名管道 匿名管道的创建需要用到pipe函数,pipe函数参数为一个数组表示的文件描述字.这个数组有两个文件描 述字,第一个是用于读数据的文件描述符第二个是用于写数 ...
- Linux 进程通信之 ——信号和信号量总结
如今最经常使用的进程间通信的方式有:信号,信号量,消息队列,共享内存. 所谓进程通信,就是不同进程之间进行一些"接触",这种接触有简单,也有复杂.机制不同,复杂度也不一 ...
- Linux进程通信学习总结
http://blog.csdn.net/xiaoweibeibei/article/details/6552498 SYSV子系统的相关概念 引用标识符:引用标识符是一个整数,表示每一个SYSV ...
- Linux进程通信的几种方式总结
进程通信的目的 数据传输 一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几M字节之间 共享数据 多个进程想要操作共享数据,一个进程对共享数据 通知事 一个进程需要向另一个或一组进程发 ...
- linux进程通信之管道
1.介绍: 1)同一主机: unix进程通信方式:无名管道,有名管道,信号 system v方式:信号量,消息队列,共享内存 2)网络通信:Socket,RPC 2.管道: 无名管道(PIPE):使用 ...
- linux 进程通信之 共享内存
共享内存是被多个进程共享的一部分物理内存.共享内存是进程间共享数据的一种最快的方法.一个进程向共享内存区域写入了数据,共享这个内存区域的全部进程就能够立马看到当中的内容. 关于共享内存使用的API k ...
- linux 进程通信之 信号
一,管道PIPE 二,FIFO通信 三,mmap通信 四,信号的概念 信号的特点:简单,但不能携带大量的信息,满足特定条件就会发生 信号的机制:进程B发送信号给进程A.信号是由内核来处理的. 信号的产 ...
- linux进程通信
e14: 进程间通信(进程之间发送/接收字符串/结构体): 传统的通信方式: 管道(有名管道 fifo,无名管道 pipe) 信号 signal System V(基于IPC的对象): ...
随机推荐
- docker部署mysql,nginx,php,并上传镜像到私有仓库
前言 最近公司准备把现有环境全部搞成容器化,所以笔者就先了解了一下docker,并搞了一搞,并把自己搞的过程记录下来.话不多说直接开干 环境说明 Centos7 Docker version 18.0 ...
- Android 把枪/PDA 扫描头自回车没用 处理方法
XML 控件加上属性 android:imeOptions="actionNone"
- 通过Kubeadm搭建Kubernetes集群
历经断断续续学习的两天,终于完成了一个简单k8s集群. 参考 https://www.cnblogs.com/edisonchou/p/aspnet_core_on_k8s_deepstudy_par ...
- django 2.0 xadmin 错误集锦
转载 django 2.0 xadmin 错误集锦 2018-03-26 10:39:18 Snail0Li 阅读数 5188更多 分类专栏: python 1.django2.0把from dj ...
- Navicat MySql 连不上 本地开发环境 MySQL8.0
原因: 新版mysql数据库的加密方式改变,进而导致Navicat连接输入的密码不能与安装时输入的密码匹配,那如何解决这个问题呢?很简单,只需要一句代码的事儿~ 1.打开MySQL 8.0 Com ...
- springboot2.0(二)
三. Web开发 3.1.静态资源访问 在我们开发Web应用的时候,需要引用大量的js.css.图片等静态资源. 默认配置 Spring Boot默认提供静态资源目录位置需置于classpath下,目 ...
- javascript新特性
让我们看看javascript中的一些新特性.本文将介绍它们的语法和相关链接,以帮助读者及时了解它们的进展.我们将通过编写一个小测试项目来演示如何快速使用这些新功能! 关于提案 提案分为五个阶段.有关 ...
- SAP UI5应用入口App.controller.js是如何被UI5框架加载的?
首先在UI5应用的manifes.json里,定义了UI5应用的入口视图为App: 调试器里的pending数组的两个元素: 实际上对应了我在App.controller.js里定义的两个依赖: 而a ...
- Java基础加强-代理
/*代理*//*代理的概念与作用*/ 代理过程架构 客户端Client原来直接调用的是Target目标类 使用代理后,现在让客户端不要调用Target,调用代理类Proxy,代理类Proxy和目标类T ...
- xshell生成公钥和私钥
一.打开你的xshell工具,工具栏有一个工具选项,点开选择新建用户密钥生成向导(如下图所示) 二. 点开之后就会如上图所示一样,点击选择下一步,出现如下,再点击下一步 点击完下一步会出现如下图所示 ...