我需要一个非常大的mmap文件的无副本重新大小,同时仍然允许并发访问读取器线程.
简单的方法是在同一个文件中使用两个MAP_SHARED映射(增长文件,然后创建包含增长区域的第二个映射),然后在所有可以访问它的读者完成后取消映射旧映射.但是,我很好奇下面的方案是否有效,如果有的话,它是否有任何优势.
疯狂的部分出现在(4).如果移动内存,旧地址将变为无效,仍在阅读内容的读者可能会突然发生访问冲突.如果我们修改读取器以捕获此访问冲突然后重新启动操作(即不重新读取错误地址,重新计算给定偏移的地址和mremap中的新基址),该怎么办.是的我知道这是邪恶的但是在我看来,读者只能成功读取旧地址的数据,或者因访问冲突而失败并重试.如果采取足够的谨慎措施,那应该是安全的.由于重新调整大小不会经常发生,读者最终会成功并且不会陷入重试循环.
如果在读取器仍具有指向它的指针时重新使用旧地址空间,则可能会出现问题.然后将没有访问冲突,但数据将是不正确的,并且程序进入不确定行为的独角兽和糖果填充的土地(其中通常既没有独角兽也没有糖果.)
但是,如果您完全控制分配并且可以确保在此期间发生的任何分配不会重复使用该旧地址空间,那么这应该不是问题,并且不应该定义行为.
我对吗?这可行吗?使用两个MAP_SHARED映射是否有任何优势?
我很难想象您不知道文件大小上限的情况。假设这是真的,您可以通过在第一次使用 mmap() 映射文件时提供该大小来“保留”文件最大大小的地址空间。当然,任何超出文件实际大小的访问都会导致访问冲突,但无论如何,这就是您希望它工作的方式——您可以争辩说,保留额外的地址空间可确保访问冲突,而不是让该地址范围开放给被其他对诸如 mmap() 或 malloc() 之类的调用所使用。
无论如何,关键在于我的解决方案,您永远不会移动地址范围,您只更改其大小,现在您的锁定围绕为每个线程提供当前有效大小的数据结构。
如果您有太多文件,以至于每个文件的最大映射使您的地址空间不足,我的解决方案将不起作用,但这是 64 位地址空间的时代,因此希望您的最大映射大小没有问题。
(只是为了确保我没有忘记一些愚蠢的事情,我确实编写了一个小程序来说服自己创建大于文件大小的映射,当您尝试访问超出文件大小的访问时会出现访问冲突,然后工作正常一旦您 ftruncate() 文件更大,所有文件都具有从第一个 mmap() 调用返回的相同地址。)
| 归档时间: |
|
| 查看次数: |
8291 次 |
| 最近记录: |