首页 文章

快速调整mmap文件的大小

提问于
浏览
8

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

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

  • 使用MAP_PRIVATE mmap文件

  • 在多个线程中对此内存执行只读访问

  • 要么获取文件的互斥锁,要写入内存(假设这是以读者可能正在读取内存的方式完成的,不会被它搞砸)

  • 或获取互斥锁,但增加文件大小并使用mremap将其移动到新地址(调整映射大小而不复制或不必要的文件IO . )

疯狂的部分出现在(4) . 如果移动内存,旧地址将变为无效,仍在阅读内容的读者可能会突然发生访问冲突 . 如果我们修改读者以捕获此访问冲突然后重新启动操作(例如,恶意,但在我看来,读者只能成功读取旧地址的数据或因访问冲突而失败并重试,该怎么办?如果足够的话注意,应该是安全的 . 由于重新调整大小不会经常发生,读者最终会成功并且不会陷入重试循环 .

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

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

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

1 回答

  • 4

    我很难想象你的情况是真的,你可以通过在首次使用mmap()映射文件时提供该大小来确定文件最大大小的地址空间"reserve" . 当然,超出文件实际大小的任何访问都会导致访问冲突,但这就是你希望它仍然工作的方式 - 你可以争辩说保留额外的地址空间可以确保访问冲突,而不是让地址范围保持开放被mmap()或malloc()之类的其他调用使用 .

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

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

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

相关问题