C中的别名内存

时间:2018-04-12 09:49:42

标签: c linux memory posix

如果我有类似绳索的数据结构:

struct rope {
  struct { char *buf; size_t len; } *segments;
  size_t len;
}

有没有办法将每个段的缓冲区连续映射到虚拟内存空间,而无需复制?我的用例是以最有效的方式将绳索转换为弦。

以下是如何使用它的示例:

char *s = rope_flatten(r);
printf("%s\n", s);
r.segments[0].buf[4] = 'x';
printf("%s\n", s); // The 5th character is now replaced with 'x'

不用说,缓冲区(至少是映射的位)不会被NUL终止。

我知道这可能是特定于平台的。如果有符合POSIX标准的东西会很棒。如果没有,Linux是我的主要目标,如果不支持,我可以回到malloc和memcpy。

1 个答案:

答案 0 :(得分:2)

在一个完美的世界中,你可以照常创建你的绳索并再次重新映射每个片段,这样你就可以看到它们是连续的第二个视图。如果您编辑一个段,没有问题,它将镜像到另一个视图。如果放大一个段,缓冲区将被透明更新。

然而,一些问题使得这一点变得不可行:

  • 虚拟内存的粒度不是按字节顺序而是逐页的,通常是4KiB,它们作为一个整体进行映射。你的代码单元可能比那个小一些。
  • 添加和删除细分仍需要修改页面表
  • 在修改时调用内核来更新映射很容易使你希望获得的任何性能优势相形见绌。
  • 可移植性问题:API是特定于操作系统的。 MMU是必需的。与VIVT缓存结合使用时的有趣效果

但是仍然存在将多个视图映射到地址空间的用例,即当数据发生变化而不是数据 structure 时,就像使用环形缓冲区一样:

通常情况下,你必须在软件中实现你的环绕逻辑,但如果你之后再次重新映射环形缓冲区的页面,你就可以获得一个只能memcpy开启的环形缓冲区。 GNU Radio采用这种机制,上面有一篇很好的博文: https://www.gnuradio.org/blog/buffers/

这篇博文让我很好奇,所以我在libvas重新实现了Linux,Windows和macOS的机制。如果你愿意,请查看。