7

我想在线程之间共享数据,并在最后一个用户完成后自动删除它。在大多数情况下,这似乎boost::interprocess::shared_ptr在一个boost::fixed_managed_shared_memory段中使用:但并非总是如此。

那么,boost::interprocess::shared_ptr线程(和进程间)是否安全?

如果我在固定地址使用我的共享内存(我很确定这在我的 64 位(嗯,48 位)地址空间中会没问题),是否可以使用普通的boost::shared_ptr(它们是线程安全)而不是?

一些澄清:

我使用的指针类型是 plain void*,(我的共享内存映射到一个固定地址)。

线程安全的问题与引用计数有关——即,是否允许同时在不同进程中复制/销毁指向同一事物的共享指针。在不同的线程中不能访问同一个共享指针,也不能访问被指针。

4

6 回答 6

5

中使用的引用计数boost::interprocess:shared_ptr是使用定义的原子计数器实现的boost/interprocess/detail/atomic.hpp,其中引用计数逻辑主要由boost/interprocess/smart_ptr/detail/sp_counted_base_atomic.hpp. 目的是以线程(和进程间)安全的方式处理引用计数。

原子操作实现因具体目标平台而异(Windows 使用 Win32 互锁 API,某些平台使用各种内联汇编等)。了解您的目标平台可能会有所帮助。我想您可能在引用计数处理中遇到了一个错误,尽管我不会指望它。

我已将上述答案限制在您想要特别解决的领域:

线程安全的问题与引用计数有关——即,是否允许同时在不同进程中复制/销毁指向同一事物的共享指针。在不同的线程中不能访问同一个共享指针,也不能访问被指针。

也就是说,我会查看您上面提到的项目或以某种方式创建“独立”boost::interprocess:shared_ptr对象(其中不同shared_ptr的 s 使用不同的引用计数引用同一对象)可能引入的错误。如果您有一些代码继续使用和/或传递原始对象指针,则这种情况很容易发生。

于 2011-04-28T05:58:41.833 回答
1

boost::shared_ptr<T>不是进程间安全的,因此在这种情况下它是否是多线程安全的没有实际意义。(此声明假定BOOST_SP_DISABLE_THREADS尚未#defined为程序运行。)

boost::interprocess::shared_ptr<T>从本质上讲,它被设计为跨进程安全的,并且本质上是多线程安全的。当最后一个引用超出范围时,可以清理指向的对象。显然,这种清理发生在用于对象的共享内存段的范围内。

由于在许多平台上boost::shared_ptr<T>使用了1.33.0 版本的无锁计数机制,除非极有可能跨进程删除shared_memory段中的对象会成功,并且似乎不受提升维护者。

于 2011-04-24T19:44:38.480 回答
0

呃。boost::shared_ptr绝对不是线程安全的。至少不比 eg 更线程安全std::vector。您可以boost::shared_ptr从多个线程中读取 a,但是一旦任何线程正在写入 a ,它就必须与其他写入者读取者boost::shared_ptr同步。

不,你不能在共享内存中使用它,它从来没有被设计成这样。例如,它使用一个所谓的“共享计数”对象来存储引用计数和删除器,并且该共享计数对象由shared_ptr代码分配,因此它不会驻留在共享内存中。此外,shared_ptr代码(以及像 vtables 之类的元数据)可能在不同进程中位于完全不同的地址,因此任何虚函数调用也将是一个问题(并且 IIRCshared_ptr在内部使用虚函数 - 或至少使用函数指针,这会导致相同的问题)。


我不知道是否boost::interprocess::shared_ptr是进程间安全的,但我很确定它不是。进程间同步非常昂贵。boost::interprocess::shared_ptr 如果不这样做,用户就有可能阻止对共享数据的访问。这样,高同步成本只需为连续多次访问支付一次。

编辑:我希望Eamon Nerbonne 在他的评论中提到的使用模式(这是线程安全的boost::shared_ptr),也可以使用boost::interprocess::shared_ptr. 不过不能肯定地说。

于 2011-03-27T03:51:19.920 回答
0

“这似乎在大多数情况下有效,在 boost::fixed_managed_shared_memory 段中使用 boost::interprocess::shared_ptr:但并非总是如此。” 如果不总是意味着删除并不总是有效:只需在线程安全容器中使用信号量即可。这个信号量并不能提高线程安全性,但可以验证甚至限制有多少用户使用数据。如果 semaphore 为 0,则没有更多用户,安全删除共享数据。如果只有一个用户,这将是 1,所以复制出用户请求的数据,删除共享容器,然后返回副本。

于 2011-04-25T08:27:27.523 回答
0

查看 shared_ptr.hpp 中的代码以及 boost 网站上的文档,似乎取消引用单个实例可能是线程安全的,也可能不是线程安全的,具体取决于第二个模板参数,它决定了要使用的内部指针类型。具体来说,“内部指针将与 typename VoidAllocator::pointer 类型相同(即,如果 typename VoidAllocator::pointer 为 offset_ptr,则内部指针将为 offset_ptr)。” 而且由于取消引用仅返回此类的 get()/get_pointer() 方法的结果,因此它可能应该完全依赖于此。如果您想要同时进行只读访问,则 Boost::shared_ptr 将起作用。对于来自多个线程的写访问,您可能必须编写自己的以 offset_ptr 为模型的包装器。

于 2011-04-25T14:17:34.613 回答
0

正如 pgroke 所暗示的(不知道为什么不赞成),核心问题是您是否从不同的线程或进程访问相同的 shared_ptr 实例。

shared_ptr (interprocess or not) 不支持这种情况,这不安全。

另一方面,shared_ptr 被设计为有多个(线程私有,或通过其他机制保护不被并发修改)共享指针实例指向同一个对象,并且这些指向同一个对象的指针的不同实例被同时修改,而无需问题。

::interprocess:: 这里主要是一个红鲱鱼 - 它不会改变指针的线程安全性,只是确保没有引用进程私有内存等的内部指针。

那么这两种情况是哪一种呢?

于 2011-04-26T00:12:42.250 回答