总结下linux下的IPC使用原理及注意事项
首先说明一下mmap函数用途:采用共享内存通信的一个显而易见的好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝1、将一个普通文件映射到内存中,通常在需要对文件进行频繁读写时使用,这样用内存读 写取代I/O读写,以获得较高的性能;2、将特殊文件进行匿名内存映射,可以为关联进程提供共享内存空间;适用于具有亲缘关系的进程之间。由于父子进程特殊的亲缘关系,在父进程
·
首先说明一下mmap函数用途:
采用共享内存通信的一个显而易见的好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝
1、将一个普通文件映射到内存中,通常在需要对文件进行频繁读写时使用,这样用内存读
写取代I/O读写,以获得较高的性能;
2、将特殊文件进行匿名内存映射,可以为关联进程提供共享内存空间;
适用于具有亲缘关系的进程之间。由于父子进程特殊的亲缘关系,在父进程中先调用mmap
(),然后调用 fork()。那么在调用fork()
之后,子进程继承父进程匿名映射后的地址空间,同样也继承mmap()
返回的地址,这样,父子进程就可以通过映射区域进行通信了。
3、为无关联的进程提供共享内存空间,一般也是将一个普通文件映射到内存中。
普通文件fd用于mmap参数:
1、最终被映射文件的内容的长度不会超过文件本身的初始大小,即映射不能改变文件的大小
2、内存的保护是以页为基本单位的,即使被映射文件只有一个字节大小,内核也会为映射分
配一个页面大小的内存,用于进程间通信的有效地址空间大小不会超过文件大小及一个页
面大小的和
3、文件一旦被映射后,调用mmap()的进程对返回地址的访问是对某一内存区域的访问,暂时
脱离了磁盘上文件的影响,只有在调用了munmap()后或者msync()时,才把内存中的相应
内容写回磁盘文件,所写内容仍然不能超过文件的大小。
A、ftok使用说明
key_t ftok( char * fname, int id ) fname就时你指定的文件名,id是子序号。
在一般的UNIX实现中,是将文件的索引节点号取出,前面加上子序号得到key_t的返回值。
如指定文件的索引节点号为65538,换算成16进制为0x010002,而你指定的ID值为38,换
算成16进制为0x26,则最后的key_t返回值为0x26010002。
当删除重建文件后,索引节点号由操作系统根据当时文件系统的使用情况分配,因此与原来
不同,所以得到的索引节点号也不同。
如果要确保key_t值不变,要目确保ftok的文件不被删除,要么不用ftok,指定一个固定的key_t值
注意:
ftok将一个已存在的路径名和一个整数标识符转换成一个key_t值。
ftok会组合三个值来产生key:
1、pathname所在的文件系统的信息。
2、该文件在本文件系统内的索引节点号。
3、id的低序8位。
key_t
的生成是以一个已存在的文件作为输入,并不是简单的字符串散列函数,必须真正存在某
个文件,才能将其位置传入ftok。
B、文件空洞是怎么回事
off_t lseek(int filedes, off_t offset, int whence);
参数 offset 的含义取决于参数 whence:
当前文件偏移量(current file offset),以下简称为 cfo,非负整数
1. 如果 whence 是 SEEK_SET,文件偏移量将被设置为 offset。
2. 如果 whence 是 SEEK_CUR,文件偏移量将被设置为 cfo 加上 offset,
offset 可以为正也可以为负。
3. 如果 whence 是 SEEK_END,文件偏移量将被设置为文件长度加上 offset,
offset 可以为正也可以为负。
注意: 对于普通文件(regular file),cfo 是一个非负整数。但对于特殊设备,cfo
有可能是负数。因此,我们不能简单地测试 lseek 的返回值是否小于 0 来判断 lseek
成功与否,而应该测试 lseek 的返回值是否等于 -1 来判断 lseek 成功与否。
if (lseek(fd, 16384, SEEK_SET) == -1)
{
printf("lseek error\n");
return -1;
}
测试结果表明,lseek并不能extend文件大小,需要write一下0的数据
/**
* 参看前面man手册中的说明,mmap()不能用于扩展文件长度。所以这里必须事
* 先扩大目标文件长度,准备一个空架子等待后面读写使用:
* 如果 offset 比文件的当前长度更大,下一个写操作就会把文件“撑大(extend)”。
* 这就是所谓的在文件里创造“空洞(hole)”。没有被实际写入文件的所有字节
* 由重复的 0 表示。空洞是否占用硬盘空间是由文件系统(file system)决定的
*/
int tmpData = 0x00;
lseek(fd,maxSize-4,SEEK_SET);
write(fd,(const void*)&tmpData,sizeof(ui32)); /* 写入一个int型数据长度 */
或者
write(fd, "\0", 1); /* 在文件最后添加一个空字符 */
也可以使用ftruncate(改变文件大小)进行设定大小。
样子后面映射后才可使用,否过会越界使用而出现死机
high memory |-------| A
| |
| |
| | memory mapped partion of file
| |
| |
low memory |-------| B
file mapped |-----------------|
|offfset| len |
|-----------------|
A' B'
以上fd[A--B]映射到[A'--B']范围内,操作[A-B]与操作下面file mapped一样
C、copy_to_user与mmap的工作原理
copy_to_user
在每次拷贝时需要检测指针的合法性,也就是用户空间的指针所指向的地址的确是一段
该进程本身的地址,而不是指向了不属于它的地方,而且每次都会拷贝一次数据,频繁
访问内存,由于虚拟地址连续,物理地址不一定会连续,从而造成CPU的CACHE频繁失效,
从而使速度降低
mmap优点:
仅在第一次使用时为进程建立页表,也就是将一段物理地址映射到一段虚拟地址上,以后
操作时不再检测其地址的合法性(合法性交由CPU页保护异常来做),另一方面是内核下
直接操作mmap地址,可以不用频繁拷贝,也就是说在内核下直接可用指针向该地址操作,
而不再在内核中专门开一个缓冲区,然后将缓冲区中的数据拷贝一次进来,mmap一般是
将一段连续的物理地址映射成一段虚拟地址,当然,也可以将每段连续,但各段不连续
的物理地址映射成一段连续的虚拟地址,无论如何,其物理地址在每段之中是连续的,
这样一来,就不会造成CPU的CACHE频繁失效,从而大大节约时间
总结:
mmap 地址影射 包括
A、内存物理地址 -- 虚拟地址
B、文件设备--虚拟地址
目的是通过 虚拟地址访问 目标地址 ,目标地址 包括 物理地址 文件设备等
更多推荐
已为社区贡献2条内容
所有评论(0)