我希望在线程之间共享数据,并在最后一个用户完成后自动删除它。这似乎在大多数情况下使用boost::interprocess::shared_ptr
段中的boost::fixed_managed_shared_memory
:但并非总是如此。
那么,是boost::interprocess::shared_ptr
线程(和进程间)-safe?
如果我在固定地址使用我的共享内存(我很确定这在我的64位(井,48位)地址空间中是可以的),是否可以使用正常相反,boost::shared_ptr
(线程安全)?
一些澄清:
我使用的指针类型是普通void*
,(我的共享内存映射到固定地址)。
线程安全的问题是关于引用计数 - 即,是否允许同时复制/销毁在不同进程中同一事物的共享指针。 不访问不同线程中的相同共享指针,不访问指针对象。
答案 0 :(得分:4)
boost::interprocess:shared_ptr
中使用的引用计数是使用boost/interprocess/detail/atomic.hpp
中定义的原子计数器实现的,其引用逻辑主要由boost/interprocess/smart_ptr/detail/sp_counted_base_atomic.hpp
实现。目的是以线程(和进程间)安全的方式处理引用计数。
原子操作实现因具体目标平台而异(Windows使用Win32 Interlocked API,某些平台使用各种内联汇编等)。了解您要定位的平台可能会有所帮助。我想你可能会在引用计数中遇到一个错误,但我不会指望它。
我已将上述答案限制在你想要专门解决的领域:
线程安全的问题是关于引用计数 - 即,是否允许同时复制/销毁在不同进程中同一事物的共享指针。不能访问不同线程中的相同共享指针,也不能访问指针。
那就是说,我会看看你上面提到的项目或者以某种方式创建'独立'boost::interprocess:shared_ptr
对象引入的bug(其中不同的shared_ptr
使用不同的refcounts引用相同的对象)。如果你有一些代码继续使用和/或传递原始对象指针,这种情况很容易发生。
答案 1 :(得分:1)
boost::shared_ptr<T>
不是进程间安全的,所以在这种情况下它是否是多线程安全的是没有实际意义的。 (该陈述假定BOOST_SP_DISABLE_THREADS
对于程序的操作没有#defined
。)
boost::interprocess::shared_ptr<T>
就其性质而言,旨在实现跨进程安全,以及多线程安全性。当最后一个引用超出范围时,可以清除指向的对象。显然,这种清理发生在用于对象的共享内存段的范围内。
由于boost::shared_ptr<T>
在许多平台上使用lock-free counting mechanism at version 1.33.0,因此除了shared_memory
段中对象的跨进程删除的最大可能性成功之外,它是不可能的,并且似乎Boost维护者不支持这些功能。
答案 2 :(得分:0)
尔。 boost::shared_ptr
绝对是不线程安全的。至少不比例如线程更安全。 std::vector
。您可以从多个线程中读取boost::shared_ptr
,但只要任何线程正在编写boost::shared_ptr
,它就必须与其他编写者和读者同步。
不,你不能在共享内存中使用它,它从未被设计成。例如。它使用一个所谓的“共享计数”对象来存储引用计数和删除器,并且该共享计数对象由shared_ptr
代码分配,因此它不会驻留在共享内存中。此外,shared_ptr
代码(以及类似vtable的元数据)可能在不同进程中处于完全不同的地址,因此任何虚函数调用也都是一个问题(IIRC shared_ptr
在内部使用虚函数 - 或者在最少的函数指针,导致同样的问题)。
如果boost::interprocess::shared_ptr
是进程间安全的,我知道,但我很确定它不是。进程间同步非常昂贵。让boost::interprocess::shared_ptr
不可以使用户阻止对共享数据的访问。这样,对于连续多次访问,只需支付一次高同步成本。
编辑:我希望期待 Eamon Nerbonne在他的评论中提到的使用模式(使用boost::shared_ptr
是线程安全的),boost::interprocess::shared_ptr
也可以。但不能肯定地说。
答案 3 :(得分:0)
“这似乎在大多数情况下都可以在boost :: fixed_managed_shared_memory段中使用boost :: interprocess :: shared_ptr:但并非总是如此。” 如果不总是意味着删除总是不起作用: 只需在线程安全容器中使用信号量即可。此信号量不会提高线程安全性,但您可以验证甚至限制用户使用数据的数量。如果信号量为0,则不再有用户,安全删除共享数据。 如果那里只有一个用户,则为1,因此请复制出用户请求的数据,删除共享容器,然后返回副本。
答案 4 :(得分:0)
查看shared_ptr.hpp中的代码以及boost网站上的文档,看起来好像取消引用单个实例可能是也可能不是线程安全,具体取决于第二个模板参数,该参数确定内部指针类型为使用。特别, “内部指针与typename VoidAllocator :: pointer类型具有相同的指针类型(即,如果typename VoidAllocator :: pointer为offset_ptr,则内部指针将为offset_ptr)。” 由于dereferences只返回此类的get()/ get_pointer()方法的结果,它应该完全取决于它。如果您想要同时进行只读访问,Boost :: shared_ptr将起作用。对于来自多个线程的写访问,您可能必须在offset_ptr之后编写自己的包装器。
答案 5 :(得分:0)
正如pgroke暗示(不确定为什么是downvotes)核心问题是你是否从不同的线程或进程访问相同的 shared_ptr实例。
shared_ptr(进程间或非进程)不支持这种情况,这不安全。
另一方面,shared_ptr被设计为具有多个(线程私有,或通过某些其他机制保护并发修改)共享指针实例指向同一对象,并且具有指向同一对象的这些指针的不同实例同时修改没有问题。
:: interprocess ::这里主要是一个red-herring - 它不会改变指针的线程安全性,只是确保没有内部指针引用进程私有内存等等。
那么这两个案例中的哪一个呢?