我正在开发一个由内存映射文件支持的线程安全队列,它大大利用了boost interprocess。我提交了它用于代码审查,并且拥有比我在这个星球上更多年经验的开发人员说他不觉得boost :: interprocess是“准备好黄金时间”并且我应该直接使用pthreads。
我认为这主要是FUD。我个人认为重新实现诸如upgradedable_named_mutex或boost :: interprocess :: deque之类的东西是荒谬的,但我很想知道其他人的想法。我找不到任何数据来支持他的说法,但也许我只是不知情或天真。 Stackoverflow启发我!
答案 0 :(得分:20)
我试图将boost :: interprocess用于一个项目并且带着复杂的感觉。我主要的不满是boost :: offset_ptr的设计以及它如何处理NULL值 - 简而言之,boost :: interprocess可以使诊断NULL指针错误真的很痛苦。问题是共享内存段被映射到进程地址空间的中间位置,这意味着“NULL”offset_ptr在取消引用时将指向有效的内存位置,因此您的应用程序将不会段错误。这意味着当你的应用程序最终崩溃时,可能在错误发生后很长时间,使调试变得非常棘手。
但它变得更糟。在内部提升::: interprocess使用的互斥量和条件存储在段的开头。因此,如果您不小心写入some_null_offset_ptr-> some_member,您将开始覆盖boost :: interprocess段的内部机制,并获得完全奇怪且难以理解的行为。编写协调多个进程并处理可能的竞争条件的代码本身就很难,所以它让人倍感疯狂。
我最终编写了自己的最小共享内存库,并使用POSIX mprotect系统调用使我的共享内存段的第一页不可读和不可写,这使得立即出现NULL错误(你浪费了一页内存但是这样一个除非你在嵌入式系统上,否则小的牺牲是值得的。您可以尝试使用boost :: interprocess但仍然手动调用mprotect,但这不起作用,因为boost会期望它可以写入它在段开头存储的内部信息。
最后,offset_ptr假设您将共享内存段中的指针存储到同一共享内存段中的其他点。如果你知道你将有多个共享内存段(我知道这将是这种情况,因为对我而言,因为我有一个可写段和一个只读段),它们会将指针存储到另一个中,offset_ptr会妨碍你你必须做一堆手动转换。在我的共享内存库中,我创建了一个模板SegmentPtr<i>
类,其中SegmentPtr<0>
将成为指向一个段的指针,SegmentPtr<1>
将指向另一个段,等等,以便它们不会被混淆(如果您在编译时知道段的数量,则只能这样做。)
您需要权衡自己实现所有内容的成本与您将用于追踪NULL错误以及可能将指针混合到不同段的额外调试时间(后者不一定是您的问题)。对我来说,自己实现它是值得的,但我没有大量使用boost :: interprocess提供的数据结构,所以显然是值得的。如果将来允许图书馆是开源的(不是由我决定),我会用链接更新,但现在不要屏住呼吸; p
关于你的同事:我没有在boost :: interprocess本身遇到任何不稳定或错误。我只是认为它的设计使得在你自己的代码中找到bug更加困难。
答案 1 :(得分:5)
我们已经使用boost :: interprocess共享内存和interprocess.synchronization_mechanisms.message_queue大约6个月了,发现代码可靠,稳定且相当容易使用。
我们将数据保存在相当简单的固定大小的结构中(尽管12个区域的大小总共为2 + gb)并且我们按原样使用了boost :: interprocess示例代码并且几乎没有问题。
在使用boost :: interprocess with windows时,我们确实发现了两个需要注意的事项。
#include <boost/interprocess/shared_memory_object.hpp>
对象,则只能通过首先重新启动Windows来增加内存映射区域的大小。这是因为boost如何使用文件后备存储。我并不是说Joseph Garvin关于他的boost :: interprocess问题的帖子无效。我认为我们的经验差异与使用图书馆的不同方面有关。我确实同意他在boost :: interprocess中似乎没有任何稳定性问题。