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的对象): ...
随机推荐
- Jfinal初次尝试及Jetty使用相关问题
Jetty介绍 Jetty官网:http://www.eclipse.org/jetty/ 参考:Jetty使用教程(一)--开始使用Jetty 1. 使用 参考上面文档,但是有些更新: echo $ ...
- 安装Docker step by step
1. 系统要求 centos7以上 使用cat /etc/redhat-release查看系统版本,我的Centos 7.6 centos-extra 仓库 enable,默认是打开的 2.安装d ...
- Spring的SSM标准配置
一.首先是web.xml文件的配置 <welcome-file-list> <!--设置默认显示登陆界面--> <welcome-file>login.jsp< ...
- sql 基础语句
一.基础 2 31.说明:创建数据库 4Create DATABASE database-name 5 62.说明:删除数据库 7drop database dbname 8 93.说 ...
- pytorch入门1——简单的网络搭建
代码如下: %matplotlib inline import torch import torch.nn as nn import torch.nn.functional as F from tor ...
- datatables初始化用法
var recordTable = $('#record_table').DataTable({ "fnInitComplete": function () { //表格初始化完成 ...
- jQuery组件封装之return this.each(function () {});
记录一下自己的调试历程 组件封装经常看到这么一段代码 $.fn.plugin = function (options) { return this.each(function (i,t) { new ...
- 获取select标签的自定义属性
$("#ddlUsers").find("option:selected").attr("fullstr"); fullstr就是自定义属性 ...
- 第三方应用如何在SAP Kyma上进行服务注册
Jerry之前的公众号文章 什么?在SAP中国研究院里还需要会PHP开发?提到了一个SAP Kyma的应用场景: 旅行兼社交达人伊森,使用经过SAP Kyma扩展之后的WordPress这个网站来写博 ...
- sql基础的基础
一.数据定义语言(DDL) create table alter table drop table create index alter index drop index create view dr ...