我需要对一个非常大的mmap文件进行无拷贝的重新调整大小,同时仍允许读取线程并发访问。
简单的方法是在同一进程中使用两个MAP_SHARED映射(扩展文件,然后创建包括扩展区域的第二个映射),然后在所有可以访问它的读取器完成后取消映射旧映射。不过,我想知道下面的方案是否可行,如果可行,是否有任何优势。
1. 使用MAP_PRIVATE映射文件。 2. 在多个线程中对此内存进行只读访问。 3. 要么获取文件的互斥锁,写入内存(假设这是以一种不会影响可能正在读取该内存的读取器的方式完成的)。 4. 要么获取互斥锁,但增加文件的大小,并使用mremap将其移动到新地址(调整映射大小而不复制或不必要的文件IO)。
疯狂的部分出现在(4)。如果移动内存,则旧地址变为无效,而仍在读取它的读取器可能会突然遇到访问冲突。如果我们修改读取器以捕获此访问冲突,然后重新启动操作(即不重新读取错误的地址,而是重新计算给定偏移量和来自mremap的新基地址的地址),那会怎么样?是的,我知道这很邪恶,但在我看来,读取器只能在旧地址成功读取数据或遇到访问违规并重试。如果采取足够的谨慎,那应该是安全的。由于调整大小不会经常发生,因此读取器最终会成功而不会陷入重试循环。
如果在读取器仍然拥有指向它的指针时重新使用了旧地址空间,则可能会出现问题。然后将没有访问冲突,但数据将不正确,并且程序进入未定义行为的独角兽和糖果填充的领域(通常既没有独角兽也没有糖果)。
但是,如果您完全控制分配并确保在此期间发生的任何分配都不会再次使用旧地址空间,则这不应该成为问题,行为也不应该是未定义的。
我对吗?这可行吗?与使用两个MAP_SHARED映射相比,是否有任何优势?
简单的方法是在同一进程中使用两个MAP_SHARED映射(扩展文件,然后创建包括扩展区域的第二个映射),然后在所有可以访问它的读取器完成后取消映射旧映射。不过,我想知道下面的方案是否可行,如果可行,是否有任何优势。
1. 使用MAP_PRIVATE映射文件。 2. 在多个线程中对此内存进行只读访问。 3. 要么获取文件的互斥锁,写入内存(假设这是以一种不会影响可能正在读取该内存的读取器的方式完成的)。 4. 要么获取互斥锁,但增加文件的大小,并使用mremap将其移动到新地址(调整映射大小而不复制或不必要的文件IO)。
疯狂的部分出现在(4)。如果移动内存,则旧地址变为无效,而仍在读取它的读取器可能会突然遇到访问冲突。如果我们修改读取器以捕获此访问冲突,然后重新启动操作(即不重新读取错误的地址,而是重新计算给定偏移量和来自mremap的新基地址的地址),那会怎么样?是的,我知道这很邪恶,但在我看来,读取器只能在旧地址成功读取数据或遇到访问违规并重试。如果采取足够的谨慎,那应该是安全的。由于调整大小不会经常发生,因此读取器最终会成功而不会陷入重试循环。
如果在读取器仍然拥有指向它的指针时重新使用了旧地址空间,则可能会出现问题。然后将没有访问冲突,但数据将不正确,并且程序进入未定义行为的独角兽和糖果填充的领域(通常既没有独角兽也没有糖果)。
但是,如果您完全控制分配并确保在此期间发生的任何分配都不会再次使用旧地址空间,则这不应该成为问题,行为也不应该是未定义的。
我对吗?这可行吗?与使用两个MAP_SHARED映射相比,是否有任何优势?