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的对象): ...
随机推荐
- Swarm系列7--存储介绍
存储介绍 1. 存储使用 与docker一样,在使用swarm服务级别的时候可以定义服务的存储需求, docker存储介绍参考: Docker之应用数据管理(volume/bind mount/tmp ...
- Spring 后台方法 重定向 与 转发
一.重定向:重定向是客户端行为,在使用时,务必使用全路径,否则可能因为外部环境导致错误 1.URL改变为重定向的URL地址 2.前台页面不能使用Ajax请求提交, 应该使用form表单提交 方法一.参 ...
- 奇妙的算法【11】LeetCode-专属算法面试题汇总
这个是LeetCode上面的编程训练专项页面,地址:https://leetcode-cn.com/explore/interview/card/top-interview-quesitons-in- ...
- C# 在运行中拖拽,改变控件大小位置类(转载)
原文地址:https://blog.csdn.net/zgke/article/details/3718989 copy的code /// <summary> /// 移动改变控件大小 / ...
- Java 18套JAVA企业级大型项目实战分布式架构高并发高可用微服务电商项目实战架构
Java 开发环境:idea https://www.jianshu.com/p/7a824fea1ce7 从无到有构建大型电商微服务架构三个阶段SpringBoot+SpringCloud+Solr ...
- js之拖拽事件
js之拖拽事件 api:https://www.runoob.com/jsref/event-ondrag.html 拖拽事件是js原生的事件,使用时在div上添加 draggable="t ...
- babel-plugin-transform-remove-strict-mode
场景:在VUE项目中,需要用到横向滚动条,在引入MUI相关的组件后,模板中的代码如下 在控制台中报错 报错内容说的是在严格模式下(strict mode)类型错误 经过推测,觉得可能是mui.js中用 ...
- openssh升级
转载:(感谢作者) centos7 升级openssh到openssh-8.0p1版本 https://www.cnblogs.com/nmap/p/10779658.html centos 7 op ...
- ajax获取后台数据出错parsererror
原因是dataType如果为json,返回的数据是text就会报错.
- haproxy??
HAProxy是一个使用C语言编写的自由及开放源代码软件,其提供高可用性.负载均衡,以及基于TCP和HTTP的应用程序代理. HAProxy特别适用于那些负载特大的web站点,这些站点通常又需要会话保 ...