ACE太大了,学习的过程充满了坎坷,我想还是从基础开始吧,撇开ACE作为网络开发库的初衷不说,ACE也是学习操作系统相关知识的良好资源,良好的跨平台性使得它必须封装操作系统提供的各种应用程序接口,所以学习ACE基础就当作是复习操作系统吧,慢慢积累,相信总有一天我能站在平流层的高度来一睹ACE的全貌。内存映射是IPC中的一种,不过其似乎作为进程通信的一种手段在实际用途中似乎用的并不多,大多数人将其作为一种简洁高效率操作文件的手段来使用。通过strace跟踪Linux各种命令的运行可以发现里面有大量的mmap调用。作为一种低层次的系统调用,Linux和Windows下的使用方式当然不同,但是ACE提供ACE_Mem_Map这个类来统一各平台的差异性,在学习ACE的过程中,我现在都不喜欢直接使用操作系统的API了,什么都想在前面加上一个"ACE_OS::",这样我内心就会觉得稳妥多了。
下面这个例子同样也是我从ACE源码包中tests目录中Mem_Map_Test测试代码总结提取出来的,加上了点自己的想法和注释,这是我喜欢的学习方式。写这段代码遇到一个问题浪费了点时间琢磨,我修改了映射到内存中的数据,然后想将修改保存到文件中,调用sync方法,数据却怎么都没有保存到硬盘中,查了查资料才找到问题的原因,原来作为IPC的一种,内存映射有一个选项用于设置修改仅对本进程有效(ACE_MAP_PRIVATE)还是对于共享有效(MAP_SHARED)。
ACE_Mem_Map::map有三个重载函数,其中一个如下:
/// Map a file specified by @a filename. int map (const ACE_TCHAR *filename, size_t length = static_cast<size_t> (-1), int flags = O_RDWR | O_CREAT, mode_t mode = ACE_DEFAULT_FILE_PERMS, int prot = PROT_RDWR, int share = ACE_MAP_PRIVATE, void *addr = 0, ACE_OFF_T offset = 0, LPSECURITY_ATTRIBUTES sa = 0);
可以看出share默认等于,这样修改就不能保存在硬盘中,此处传递MAP_SHARED给map函数就好了,但是由于C++不支持"int share = MAP_SHARED"这样传递参数(python是支持的),所以必须将前面的默认参数都填起,这一点在拥有众多默认参数的函数上感觉很糟糕,希望未来的C++能添加这一特性。另外一个问题是我不能在这个文件后面添加一些数据,操作时没有错误,但是同步后,修改不会被保存到硬盘中,这一点有待于进一步研究。其实是可以附加数据的,只不过ACE_Mem_Map::size返回的可不是文件中字符的个数,它的默认值似乎是1000,如果使用mmap.addr()+mmap.size()偏移想在文件的最后位置附加数据就不能被保存到硬盘中,可能是sync默认只保存1000个字节吧。
#include "ace/Mem_Map.h"#include "ace/ACE.h"#include "ace/OS_NS_string.h"#include "ace/OS_NS_unistd.h"#include "ace/OS_NS_fcntl.h"#include "ace/OS_Memory.h"#include "ace/Log_Msg.h"
int main(int, char**){ const char filename[] = "memmap.txt";
//注意O_TRUNC这个选项会将文件清空 ACE_HANDLE file_handle = ACE_OS::open (filename, O_RDWR | O_CREAT | O_TRUNC, ACE_DEFAULT_FILE_PERMS);
if (file_handle == ACE_INVALID_HANDLE) { ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("Open failed for %s/n"), filename), -1); } else { ACE_DEBUG((LM_DEBUG, "Open %s successfully/n", filename)); }
char buf[128] = "ecy fu";
//往文件中写数据,如果文件为空然后就将其映射到内存中会导致运行时异常 ACE_OS::write(file_handle, buf, ACE_OS::strlen(buf));
//关闭文件 ACE_OS::close (file_handle);
ACE_Mem_Map mmap;
//注意参数的填写哦 if (mmap.map (filename, -1, O_RDWR, ACE_DEFAULT_FILE_PERMS, PROT_RDWR, int share = MAP_SHARED) == -1) ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%n: %p %s/n%a"), ACE_TEXT ("mmap"), filename), -1);
//获取开始指针,这样就可以通过指针来操作文件的内容了,显得特别方便 char* ptr = (char *) mmap.addr ();
ACE_DEBUG((LM_DEBUG, "read from file: /n"));
for(int i =0; i < mmap.size(); ++i, ++ptr) ACE_DEBUG((LM_DEBUG, "%c", *ptr));
ACE_DEBUG((LM_DEBUG, "/n"));
//修改前三个字符 ptr = (char *) mmap.addr (); *ptr = ':'; *++ptr = '-'; *++ptr = ')';
//将内存中的修改同步到硬盘文件中 if (mmap.sync() == -1) ACE_DEBUG((LM_DEBUG, "sync error!!!/n"));
ptr = (char *) mmap.addr ();
ACE_DEBUG((LM_DEBUG, "read from file: /n"));
for(int i =0; i < mmap.size(); ++i, ++ptr) ACE_DEBUG((LM_DEBUG, "%c", *ptr));
ACE_DEBUG((LM_DEBUG, "/n"));
//将数据同步到文件中 if (mmap.sync() == -1) ACE_DEBUG((LM_DEBUG, "sync error!!!/n"));
mmap.close();
//ACE_OS::unlink(filename);
return 0;}