【问题标题】:Access object in interprocess shared memory without violating strict aliasing rules在不违反严格的别名规则的情况下访问进程间共享内存中的对象
【发布时间】:2019-09-16 12:01:58
【问题描述】:

我有多个用 C++17 编写的程序,在 Linux 上运行。

一个程序在 /dev/shm/ 下创建一个文件并将其映射到它的内存空间。然后它继续使用placement-new在共享内存中初始化一个POD对象。

其他进程将打开这些文件并将其映射到它们的内存空间以访问该对象。目前,我正在使用 C 风格的强制转换,它有效,但我相信根据 C++ 别名规则,它在技术上是未定义的行为,因此这可能会在未来版本的 GCC 中中断。

编译器不知道该内存位置存在对象。通常,我会通过调用placement-new 将这一点传达给编译器,但在这种情况下,这将初始化现有对象(我相信这也是未定义的行为)。

我应该如何在不违反严格的别名规则的情况下访问该对象? 这是std::launder 的用例吗?

【问题讨论】:

  • 新放置不会初始化 POD。但是,您应该采取特殊措施来防止诸如互斥锁之类的竞争条件。这在很大程度上取决于您的设计。

标签: c++ ipc c++17 shared-memory interprocess


【解决方案1】:

mmap 函数返回一个 void 指针,严格的类型别名规则不适用于 void 指针,因为它们不指向实际类型,但需要在访问之前强制转换为某些东西。因此,在 C++ 中,在 void 指针上使用类似 C 的强制转换或更好的 static_casts 是完全合法的。

但是如果您访问共享内存中的数据,它可能会成为一个优化问题。如果他可以看到所有调用,则允许您的编译器假定 RAM 没有被某些东西更改。因此,您必须在其周围放置例如互斥锁,以确保您的编译器无法看到所有可能的访问,并且必须重新加载数据。

【讨论】:

  • 但是一个对象只能通过在堆栈上作为局部变量或通过 new 表达式创建它来存在。这就是为什么在 C++ 中仅仅 malloc 一些内存然后将其转换为您想要的任何对象类型是无效的。为什么在 mmap 内存的情况下这是合法的?
  • @SumDood 您不应在堆栈上创建对象,而是使用指针。因此,在您使用的所有进程中,除了一个进程: myType *var = static_cast(shared_mem+offset);在一个过程中: myType *var=new (shared_mem+offset)(myType);
猜你喜欢
  • 1970-01-01
  • 2016-02-24
  • 1970-01-01
  • 2017-02-25
  • 2020-04-11
  • 2015-01-16
  • 2021-10-21
相关资源
最近更新 更多