快速调整mmap文件的大小

时间:2012-01-02 17:58:48

标签: c++ c linux mmap

我需要一个非常大的mmap文件的无副本重新调整大小,同时仍然允许并发访问读者线程。

简单的方法是在同一个文件中使用两个MAP_SHARED映射(增长文件,然后创建包含增长区域的第二个映射),然后在所有可以访问它的读者都取消映射旧映射完了。但是,如果下面的方案可行,我很好奇,如果有的话,它是否有任何优势。

  1. 使用MAP_PRIVATE
  2. 制作文件
  3. 对多个线程中的此内存进行只读访问
  4. 获取文件的互斥锁,写入内存(假设这样做的方式是读者可能正在读取内存,不会被它弄乱)
  5. 或获取互斥锁,但增加文件大小并使用mremap将其移动到新地址(调整映射大小而不复制或不必要的文件IO。)
  6. 疯狂的部分出现在(4)。如果移动内存,旧地址将变为无效,仍在阅读内容的读者可能会突然发生访问冲突。如果我们修改读取器以捕获此访问冲突然后重新启动操作(即不重新读取错误地址,重新计算给定偏移量的地址和mremap中的新基址),该怎么办。是的我知道这是邪恶的但是在我看来,读者只能成功读取旧地址的数据,或者因访问冲突而失败并重试。如果采取足够的谨慎措施, 应该是安全的。由于重新调整大小不会经常发生,读者最终会成功,而不会陷入重试循环。

    如果在阅读器仍有指针的情况下重新使用旧的地址空间,则可能会出现问题。然后将没有访问冲突,但数据将是不正确的,程序进入不确定行为的独角兽和糖果填充土地(其中通常既没有独角兽也没有糖果。)

    但是如果你完全控制了分配并且可以确保在此期间发生的任何分配都不会重复使用那个旧的地址空间,那么这不应该是一个问题,并且行为不应该是未定义的。 / p>

    我是对的吗?这可行吗?使用两个MAP_SHARED映射是否有任何优势?

1 个答案:

答案 0 :(得分:4)

我很难想象一个你不知道文件大小的上限的情况。假设这是真的,您可以通过在首次使用mmap()映射文件时提供该大小来“保留”地址空间以获得文件的最大大小。当然,超出文件实际大小的任何访问都会导致访问冲突,但这就是你希望它的工作方式 - 你可以说保留额外的地址空间确保访问违规而不是而不是让那个地址范围开放供其他调用mmap()或malloc()。

无论如何,关键在于我的解决方案,你永远不会移动地址范围,你只需改变它的大小,现在你的锁定是围绕为每个线程提供当前有效大小的数据结构。

如果你有这么多文件,每个文件的最大映射会使你超出地址空间,我的解决方案不起作用,但这是64位地址空间的年龄,所以希望你的最大映射大小没问题

(为了确保我没有忘记一些愚蠢的东西,我确实写了一个小程序来说服自己创建大于文件大小的映射,当你尝试超出文件大小访问时会产生访问冲突,并且一旦ftruncate()文件变得更大,所有都使用从第一个mmap()调用返回的相同地址,然后工作正常。)

相关问题