接下来就是映射内存 memory map
映射内存和共享内存非常得类似
它的基本机制其实是一样的
唯一的差别就是映射内存
它将会将一个文件
映射到我们这个内存区域里边
文件呢会被分割成页面的大小
映射进来
这个时候就可以向内存数据一样
来操纵这个文件
这个时候效率会更高
使用mmap()完成这个基本的映射
这里边有一些参数
Addr就表示映射目的地的地址
参数length就表示映射内存的大小
prot表示的就是映射内存的保护权限
读权限 写权限等等执行权限
flags就是映射的时候它的附加的选项
fd就是待映射文件的文件描述符
offset就是你指定映射的那个文件
在那个文件中的偏移量
从什么地方开始映射 很典型
当你文件很大的时候只能映射一部分
这个offset就有用了
函数返回值呢
返回的就是映射文件映射以后
在内存中的基地址
如果失败了当然就会返回失败的标记
后来你又不用这个映射内存
那么你就可以调用munmap()
释放这个映射内存
传一个地址进去
传这个映射内存的长度尺寸
就OK了
映射的内存如果想要同步
就可以调用msync()这个函数
完成它的同步动作
我们看读写映射内存的实例
在这个程序里
我们定义一个常量mapped_size
4096个字节
实际映射的数目
是映射的尺寸除以整数的尺寸
我们实际上就将映射1024个整数（注：int尺寸为32位）
刚好是一个内存页面 就这个意思
主函数 我们首先打开一个文件
作为内存映射的对象
我们要确保这个文件的尺寸
足够存储1024个整数
所以我们定位到文件的结尾
然后朝里边写一个空白
重新再定位到开头
我们只是write() 写进去
就保证这个文件会构造出来
4096个字节
这个代码做的就是这个事
我们打开这个文件作为映射内存的对象
然后确保文件的尺寸
能够容纳1024个整数 就4096个字节
一开始把这个文件开出来
否则的话你一开始创建这个文件
数据是没有的 它的文件尺寸是0
你想映射的话 映射就不会成功
因为尺寸不够 尺寸不满足它的要求
所以我们要一开始
就把这个文件构造出来
有4096个字节 做的就这个事
然后我们会把它
文件指针定位到文件的开头
再然后我们就调用mmap()
去映射这个文件
把它映射到内存里
然后就可以用base这个指针来访问它
我们把它转型成指向整数的指针
来访问它 对吧
我们按照这个模式映射
映射完以后
那个文件描述符就可以关掉了 不用了
我们就可以使用映射内存的指针
基地址那个指针来操纵它就OK了
现在我们fork一个子进程
fork一个子进程以后
我们在子进程里边
向这个映射内存里写数据
这个映射内存的写数据
它就会反映到我们的磁盘文件里
那个磁盘文件里
这些数据就会被写进去
我一个for循环
从头开始写1024个整数
第一个整数是0 第二个整数是1
第三个整数是2
最后一个整数是1023
我就写这么多个整数
把它写进去 就完了
这就是一个for循环
因为整个循环内部要做的事情
都在循环头部做完了
所以循环体本身是空的
做完了以后 我们就munmap()
取消这个映射
在父进程里边呢
我们首先睡10秒钟
等到那边都写完了
我们就写一个for循环
一个一个地从这个文件中
把这个数据读出来 就完事了
因为这个文件映射是在我们构造
这个子进程之前就做完了
所以这个映射的内存
自动地被父进程和子进程所共享
父进程和子进程就可以使用
那个映射的内存来交换数据了
这个显然要比使用管道要方便一些 为啥
因为第一 它可以和文件挂在一块
第二 这个尺寸你可以定得很大
当你要传较大量数据的时候
这个技术就有用了
刚才不说了嘛 那个管道那个东西
它一般的数据传输就只有一个页面
管道的数据传输 它是受限的
容量是有限的
而我们映射内存 只要内存是足够的
设多大其实都没关系
当然要比管道要更灵活
接下来的一个进程间通讯机制
就是消息队列
它可以在两个进程之间
传递二进制的块数据
特别需要说明的是
数据块本身 它是有一个类别信息的
接收方可以根据这个消息的类别
然后选择性地处理这些消息
消息队列的创建和获取的函数
叫msgget()
和进程信号量
和我们刚才讲到的共享内存都差不多
函数名字看上去都差不多
使用方式也都差不多
都有key 有个键值 msgget()
很多标志都是共用的
有时候需要命令控制的时候
连命令控制都是共用的
msgsnd()就是将消息
添加到我们消息队列里
把一个消息发送过去
但是发送的时候你要注意
当然会有一个msgid
还有一个msg_ptr
它是指向你要发送的那个消息的
消息数据本身的长度
要通过第三个参数传进去
第四个参数就是发送消息的时候
它的那个发送标志
msg_ptr就是指向那个消息缓冲区的
一个指针
那个消息缓冲区的格式是这个样子
是一个结构体 有两个字段
第一个字段是这个消息的型
也就是消息的类别
第二个字段呢
就是这个消息的缓冲区的长度
它的长度是受限的 512个字节
一般来讲 传一个消息
不会有太长的
只是一个简短的信息传递机制
不能传递太复杂的消息
如果过多 那么消息队列处理的模式
就不如我们的映射内存了
不如我们共享内存了 对吧
就这个意思
消息队列传短消息的
用msgrcv()从消息队列里获取数据
用msgctl()来控制消息队列里面的
某些特定的属性
它的控制方式和原先进程信号量类似
你就拿过来按照这个方式用 就OK了