进程间通信(IPC)-mmap基本概念
想了解的mmap的前提需要知道存储映射I/O:
解释:
存储映射I/O (Memory-mapped I/O) 使一个磁盘文件与存储空间中的一个缓冲区相映射。于是当从缓冲区中取数据,就相当于读文件中的相应字节。于此类似,将数据存入缓冲区,则相应的字节就自动写入文件。这样,就可在不适用read和write函数的情况下,使用地址(指针)完成I/O操作。
使用这种方法,首先应通知内核,将一个指定文件映射到存储区域中。这个映射工作可以通过mmap函数来实现。
对于上面的话通俗的将就是将磁盘文件映射到存储空间中(虚拟地址空间)中去,这样的话我们就可以通过指针来操控映射区,从而进行I/O。
所以首先先来看看mmap函数原型
注:offset:他就是文件的偏移,因为我可以把整个文件映射过去,我也可以把部分文件映射过去,这个时候就需要offset了。
对于mmap函数有了大概的了解后我们来看他的使用
1.首先使用mmap创建一个映射区
我们可以看到创建了新文件,并且里面的内容是hell因为我给的文件大小是4,所以后面mmap没有显示。
下面我列举一些关于使用mmap的注意事项
1. 创建映射区的过程中,隐含着一次对映射文件的读操作。
2. 当MAP_SHARED时,要求:映射区的权限应<=文件打开的权限(出于对映射区的保护)。而MAP_PRIVATE则无所谓,因为mmap中的权限是对内存的限制。
3. 映射区的释放与文件关闭无关。只要映射建立成功,文件可以立即关闭。
4. 特别注意,当映射文件大小为0时,不能创建映射区。所以:用于映射的文件必须要有实际大小!! mmap使用时常常会出现总线错误,通常是由于共享文件存储空间大小引起的。
5. munmap传入的地址一定是mmap的返回地址。坚决杜绝指针++操作。
6. 如果文件偏移量必须为4K的整数倍
mmap创建映射区出错概率非常高,一定要检查返回值,确保映射区建立成功再进行后续操作。
(上述展示了文件和映射区的交互)2.使用mmap进行父子间通信
可以看出父进程读出了p的1000,说明进程间通信了,但是val父子进程个是各的,因为全局变量不是父子进程共享的,共享的只有打开的文件和mmap建立的映射区。
注意如果把map_share改成private的话则映射区不共享了,独有的。。
这个进程间通信的例子是由血缘关系的进程间的通信
3.匿名映射区,前面的两个例子都是创建文件建立的映射区,但是这个文件在映射区建立好以后进行进程间通信的时候就没有意义了,所以我们来看不使用文件创建匿名映射区
方法1:使用宏只需要将2的 代码改动一下就好,代码如下
注意匿名映射区的fp给成-1就可以了这里我没有给
可以看出程序效果是一样的。
注意宏这种方法只能在linux系统中使用。没有文件的情况下映射区的大小由你自己给
方法2:系统目录dev/zero,字符设备文件,是一个伪文件没有实际大小,但是你想要多大他就可以给你提供多大,所以可以用它来创建映射区,还有一个对应的文件dev/null,好比一个无底洞,什么东西都可以扔进去
同理只需要打开dev/zero这个文件就可以创建映射区了,自己下去
4.无血缘关系的进程间通信,两个进程通信
实质上mmap是内核借助文件帮我们创建了一个映射区,多个进程之间利用该映射区完成数据传递。由于内核空间多进程共享,因此无血缘关系的进程间也可以使用mmap来完成通信。只要设置相应的标志位参数flags即可。若想实现共享,当然应该使用MAP_SHARED了。
注意:这里给两个进程创建映射区的文件必须是相同的文件。左边的进程在写数据,右边的进程在读数据,实现了无血缘关系进程间通信
最后其实文件也可以进程进程间通信(有血缘关系和无血缘关系都可以,打开同一个文件分别进行读写操作这个自己去验证)。
以上就是mmap的简单的用法。