2011-06-17 34 views
2

下午好,我们正在尝试构建一个由Windows和Linux 32位应用程序使用的内存映射文件缓存程序原型。每当我们运行原型时,当我们尝试调用UnMapViewOfFile来取消映射缓存的内存映射文件区域时,我们会得到错误487(错误无效地址)。我们认为这是因为我们试图取消映射前一个未映射区域。我们想知道是否可以忽略这个错误信息。是否可以忽略UnMapViewOFFile()的错误487(ERROR_INVALID_ADDRESS)?

我们尽我们所能,以确保对MapViewOfFile每次调用由UnMapViewOfFile以下列方式相匹配,我们每次调用MapViewOfFile,我们使用下面的代码:

std::deque<Range> ranges_type; 

std::multimap<char *,Range> mmultimap; 

MapPtr = (char*)::MapViewOfFile(hMapping, 
           FILE_MAP_WRITE | FILE_MAP_READ, 
           0, baseoff, 
           mappedlength); 
if (MapPtr == 0){ 
    DWORD lasterr = GetLastError(); 
    ErrorMessage(lasterr); 
} 

ranges_type.insert(RangeDeque::value_type(
         PreviousNCopy, 
         PreviousN, 
         adjustedptr + n, 
         MapPtr, 
         TimeStamp, 
         mappedlength)); 

mmultimap.insert(RangeMultiMap::value_type(
        MapPtr, 
        Range(PreviousNCopy, 
          PreviousN, 
          adjustedptr + n, 
          MapPtr, 
          TimeStamp, 
          mappedlength))); 

每次我们取消映射内存映射文件区域,我们用下面的摘录:

typedef std::multimap<char *,Range>::const_iterator I; 
numerased = 0; 
std::pair<I,I> b = mmultimap.equal_range(TmpPrevMapPtr); 
for (I i=b.first; i != b.second; ++i){ 
    std::dequeue<Range>::iterator iter; 
    iter = std::lower_bound(ranges_type.begin(), 
          ranges_type.end(), 
          i->second); 
    if (iter != ranges_type.end() && !(i->second < *iter)){ 
     ranges_type.erase(iter); 
     numerased++; 
    } 
} 

erasecount = mmultimap.erase(TmpPrevMapPtr); 
retval = UnmapViewOfFile(TmpPrevMapPtr); 
if (retval == 0){ 
    DWORD lasterr = GetLastError(); 
    ErrorMessage(lasterr); 
} 

类范围如下:

class Range { 
public: 
    explicit Range(int item){ 
     mLow = item; 
     mHigh = item; 
     mPtr = 0; 
     mMapPtr = 0; 
     mStamp = 0; 
     mMappedLength = 0; 
    } 
    Range(int low, int high, char* ptr = 0,char* mapptr = 0, int stamp = 0, int currMappedLength = 0){ 
     mLow = low; 
     mHigh = high; 
     mPtr = ptr; 
     mMapPtr = mapptr; 
     mStamp = stamp; 
     mMappedLength = currMappedLength; 
    } 

    Range(const Range& r): 

    bool operator==(const Range& rhs) const{ 
     return (mLow <= rhs.mLow && mHigh >= rhs.mHigh); 
    } 
    bool operator<(const Range& rhs) const{ 
     return mHigh < rhs.mHigh;  
    } 

public: 
    int mLow; 
    int mHigh; 
    char* mPtr; 
    char* mMapPtr; 
    int mStamp; 
    int mMappedLength; 
}; // class Range 

感谢您阅读本文。

+0

我们的容器类的STL原型如下所示:std :: deque ranges_type; std :: multimap mmultimap;上面定义了类Range,谢谢。 – Frank

+0

我们想知道是否将char * MapPtr的multimap键更改为struct cache {char * MapPtr,int Marked; };我们每次修改缓存内存映射文件区域的映射时,修改多映射的键值?然后,每次在我们调用UnMapViewOfFile(TmpPrevMapPtr)之前,我们都可以检查是否该指针之前未被映射。这可能与STL multimap类有关吗?谢谢。 – Frank

+0

当然可以忽略这个错误,它只会告诉你unmap操作不起作用,因为地址没有被映射。或者,措辞不同,你想怎么处理这个错误呢?没有什么可以做的(首先避免它)。 – Damon

回答

4

我们尝试了取消映射一个previouslu映射的区域

这是一个错误,期。您通过修复错误来“忽略”错误。

或者,只要用if测试忽略它。 Win32函数告诉你需要修复的错误,但是如果你想忽略它告诉你的东西,当然没有人会阻止你这样做。

+0

@Billy O“Neal,谢谢你的回答,我们同意你的看法,这个bug必须修复,你认为如果把multimap key从char * MapPtr改为struct cache {char * MapPtr,int Marked; };在每次我们取消映射缓存的内存映射文件区域时,我们在哪里标记/修改multimap的键?然后,在我们调用UnMapViewOfFile(TmpPrevMapPtr)之前,我们可以通过查看标记的整数来检查该指针是否已经被取消映射这是可能的与STL multimap类在订单(常量)的时间?谢谢你的回答。 – Frank

+0

@Frank:为什么不使用像'shared_ptr'这样做的所有苦差事为你工作?你可以写你自己的参考计数,但有很多已经编写的解决方案。 –

+0

@Billy ONeal,谢谢你的建议,我们会看看shared_ptr。谢谢你的帮助。 – Frank

1

您需要修复导致内存区域未被映射两次的潜在错误。毕竟这样考虑:

  • 你映射的内存区域位于地址0x42000000(A叫它)
  • 您在0x42000000
  • 取消映射你在同一地址映射内存B的区域0x42000000
  • 您在0x42000000处双取消映射A - 仅此时B未映射
  • 您尝试访问B并崩溃。

你需要弄清楚你在哪里解决这个问题,解决这个问题,或者最终发生这样的事情。如果你隐藏了这个错误,它会让这个更难以调试。

现在,您的会计很适合调试目的,但它没有解决根本原因;你首先不能很好地跟踪你的内存映射。对于你发布的代码的一小部分,你不可能评论更多,但你应该查看代码,以确定何时需要修改映射/取消映射;当它太迟时,不要试图压制双释放器。毕竟,如果你将这个内存映射双重释放,这是否意味着你的代码认为它仍然被映射?在这种情况下,是什么阻止访问后无问题的发生:

  • 地图A在0x42000000
  • 取消映射在0x42000000
  • 访问A(崩溃!)
  • 尝试双取消映射在0x42000000(没有达到,由于崩溃)

或者:

  • 你映射的内存区域(地址为0x42000000
  • 叫它A)
  • 您取消映射在0x42000000
  • 您在同一地址0x42000000
  • 思维的仍然是映射内存映射B的区域A,你在0x42000000和进入菜单B访问内存来代替。混乱!或者可能是数据损坏!
+0

@BDonlan,谢谢你的深思熟虑的回答。我们的原型中有两个STL缓存,std :: deque ranges_type; std :: multimap mmultimap。每次我们尝试取消映射一个内存区域时,我们会擦除ranges_types缓存和mmultimap缓存中的项目。为了访问内存X区域,它必须位于ranges_type缓存中,或者我们必须取消映射最近最少使用的内存区域,然后调用MapViewOfFile来映射另一个内存区域。从理论上讲,在未映射X之后访问X是不可能的。谢谢。 – Frank

+0

@Frank,如果不可能访问X,为什么在映射X之后可以取消映射? Therein谎言你的bug :) – bdonlan

+0

@BDonlan,我道歉我还有更多的问题。我们同意我们的2个STL缓存系统没有错误。我们是否应该更改为具有多个索引的单个BOOST MultiIndex缓存?我们试过这样做,但即使在Windows发行版中,STL似乎也比BOOST多索引代码运行得更快?也许,我们没有正确使用BOOST容器类。如果您愿意,我们可以将我们的代码发布到URL系统并为您提供URL链接。谢谢你的深思熟虑的答案。 – Frank

相关问题