在C++中实例化共享内存对象

9
我们需要多个程序调用一个公共库中的函数。库函数访问和更新一个公共全局内存。每个程序的函数调用都需要看到这个公共全局内存。也就是说,一个函数调用需要看到先前任何函数调用的更新,即使是从另一个程序调用的。
由于兼容性原因,我们对共享库公开的函数操作有几个设计约束:
  • 任何声明为全局的数据项(包括标准数据类型和对象)必须对所有调用者可见,无论代码在哪个线程中运行。
  • 在函数中声明的任何数据项仅在该函数内部可见。
  • 任何标准数据类型或任何类的实例都可以出现在本地或全局或两者兼有。
一个解决方案是将库的公共全局内存放在命名的共享内存中。第一次库调用会创建命名的共享内存并初始化它。随后的程序调用会获取共享内存的地址,并将其用作指向全局数据结构的指针。在全局声明的对象实例需要动态分配到共享内存中,而在本地声明的对象实例可以放置在调用线程的堆栈或本地堆中。问题在于,全局内存中初始化的对象可以创建并指向分配(new)额外内存的子对象。这些新分配也需要在共享内存中,并被所有库调用者看到。另一个复杂性在于,这些包含字符串、文件等的对象也可以在调用程序中使用。当在调用程序中声明时,对象的内存属于调用程序本地,而不是共享的。因此,对象的代码需要处理这两种情况。
我们认为解决方案将需要覆盖全局放置 new、常规 new 和 delete 运算符。我们找到了一个内存管理系统的设计,看起来似乎能够工作,但我们没有找到任何实际的实现。如果有人知道 Nathan Myers 的内存管理设计的实现(http://www.cantrip.org/wave12.html?seenIEPage=1),我将感激提供链接。或者如果有人知道另一个适应动态分配对象的共享内存管理器,我也很想了解。我已经检查了 Boost 库和所有其他我能找到的来源,但似乎没有一个能做到我们需要的。我们希望不必自己编写一个。由于性能和稳健性很重要,使用经过验证的代码会很好。提前感谢任何想法/帮助。
感谢关于ATL和OSSP库的建议。我正在检查它们,尽管我担心如果我们的目标是Unix,ATL可能过于Wincentric。
现在还有一件事情对我们来说似乎很清楚。由于对象可以在执行期间动态创建,因此内存管理方案必须能够分配额外的共享内存页。这现在开始看起来像一个完整的堆替换内存管理器。

2
这个问题的规范解决方案不是创建一个服务器,让客户端应用程序使用吗?比起折腾共享内存,这要容易得多,而且由于你提到的原因,共享内存也不太可能奏效。 - anon
是的。重新设计应用程序将是解决问题最简单的方法。不幸的是,由于与其他组件兼容性的设计限制,我们没有这个选项。 - BillC
编写自己的堆管理器是疯狂之路。每当我参与一个项目时,人们会说“我们做不到”,而“它”显然是正确的解决方案,他们都被证明是错的。我不是奥巴马先生的特别粉丝,但在这种情况下,他是正确的。 - anon
4个回答

1

1
正如我在帖子中提到的那样,我们研究了Boost库。不幸的是,它没有实现我们所需的功能。但它引导我们找到了一些有前途的资源,比如我在帖子中提到的链接。 - BillC

1

我相信你已经发现了,这是一个非常复杂的问题,而且很难正确地实现。根据我的经验,以下是一些提示。首先,您肯定需要使用信号量来同步对共享内存分配的访问。其次,多个进程对共享对象所做的任何修改也需要受到信号量的保护。最后,在定义对象和数据结构时,需要考虑从共享内存区域的起始处的偏移量,而不是绝对指针值(尽管如果需要,可以选择固定映射地址,因为通常情况下内存可以在每个附加的进程中映射到不同的地址)。将所有内容以稳健的方式组合在一起是困难的部分。如果进程意外死亡,基于共享内存的数据结构很容易变得损坏,因此通常需要一些清理/恢复机制。


1
你说得很对。这个问题很复杂,所以我们不想从头开始编写代码。 - BillC

0

OSSP mm - 共享内存分配:

man 3 mm


0
还要学习互斥锁和信号量。当两个或多个实体需要共享内存或数据时,需要有一个“交通信号”机制来限制写访问仅限于一个用户。

谢谢。我们明白这需要线程安全,并已实现互斥锁来控制访问。我们主要的问题是如何确保某些对象与它们实例化的任何对象一起分配在共享内存中,而同一对象的其他实例则分配在本地。 - BillC
混合使用进程本地和共享内存,就像您所描述的那样,似乎是灾难的配方。定义更正式的进程间通信协议可能是更好的方法。 - An̲̳̳drew

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接