我想在线程之间共享数据,并在最后一个用户使用完数据后自动删除数据。大多数情况下,在 boost::fixed_management_shared_memory
段中使用 boost::interprocess::shared_ptr
似乎是有效的:但并非总是如此。
那么,boost::interprocess::shared_ptr 线程(和进程间)安全吗?
如果我在固定地址使用共享内存(我非常确定这在我的 64 位(好吧,48 位)地址空间中没问题),是否可以使用普通的 boost::shared_ptr
(这是线程安全的)?
一些说明:
我使用的指针类型是普通的void*
(我的共享内存映射到固定地址)。
线程安全的问题是关于引用计数——即是否允许同时在不同进程中复制/销毁指向同一事物的共享指针。 不在不同线程中访问同一个共享指针,并且不访问被指针。
I want to share data between threads, and have it automatically deleted when the last user is done with it. This seems to work, most of the time, using boost::interprocess::shared_ptr
in a boost::fixed_managed_shared_memory
segment: but not always.
So, is boost::interprocess::shared_ptr
thread (and interprocess) -safe?
If I'm using my shared memory at a fixed address (I'm pretty certain this is going to be okay in my 64-bit (well, 48-bit) address space), is it possible to use a normal boost::shared_ptr
(which are threadsafe) instead?
some clarification:
The pointer type I use is plain void*
, (my shared memory is mapped to a fixed address).
The question of threadsafety is about the reference count -- i.e., whether copying/destroying shared pointers to the same thing in different processes at the same time is permitted. Not access to the same shared pointer in different threads, and not access to the pointee.
发布评论
评论(6)
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
对象(其中不同的shared_ptr
)使用不同的引用计数引用同一对象)。如果您有一些代码继续使用和/或传递原始对象指针,则很容易发生这种情况。The reference count used in
boost::interprocess:shared_ptr
is implemented using an atomic counter defined inboost/interprocess/detail/atomic.hpp
with the refcount logic mainly implemented byboost/interprocess/smart_ptr/detail/sp_counted_base_atomic.hpp
. The intent is to have the refcount be handled in a thread (and interprocess) safe manner.The atomic operation implementations differ depending on the specific target platform (Windows uses the Win32 Interlocked APIs, some platforms use various inline assembly, etc). It might be helpful to know what platform you're targeting. I suppose that you may be running into a bug in the refcount handling, though I wouldn't count on it.
I've restricted the above answer to the area you wanted specifically addressed:
That said, I'd look at bugs introduced possibly by the items you mention above or by somehow creating 'independent'
boost::interprocess:shared_ptr
objects (where differentshared_ptr
s refer to the same object using different refcounts). This situation can be easy to have happen if you have some code that continues to use and/or pass around the raw object pointer.boost::shared_ptr
不是进程间安全的,因此在这种情况下它是否是多线程安全的是没有意义的。 (此语句假设BOOST_SP_DISABLE_THREADS
尚未为程序的操作#define
。)boost::interprocess::shared_ptr
是,从本质上讲,它被设计为跨进程安全,并且本质上是多线程安全的。当最后一个引用超出范围时,所指向的对象可以被清理。显然,这种清理发生在用于对象的共享内存段的范围内。由于
boost::shared_ptr
使用 ,除非极有可能跨进程删除shared_memory
段中的对象,否则不太可能会成功,并且 Boost 维护者似乎不支持该功能。boost::shared_ptr<T>
is not interprocess safe, so whether it is multithread safe in this context is moot. (This statement assumes thatBOOST_SP_DISABLE_THREADS
has not been#defined
for the program's operation.)boost::interprocess::shared_ptr<T>
is, in its very nature, designed to be cross-process safe, as well as multithread safe in its nature. When the last reference goes out of scope, the pointed-at object can be cleaned up. Obviously, this cleaning up happens within the bounds of the shared memory segment used for the object.Since
boost::shared_ptr<T>
uses a lock-free counting mechanism at version 1.33.0 on many platforms, it is unlikely except by the remotest of chances that cross-process deletion of an object in ashared_memory
segment would succeed, and does not appear to be supported functionality by the Boost maintainers.呃。
boost::shared_ptr
绝对不是线程安全的。至少不比 std::vector 更线程安全。您可以从多个线程读取boost::shared_ptr
,但只要任何线程正在写入boost::shared_ptr
,它就必须与其他编写器同步和< /em>读者。不,你不能在共享内存中使用它,它从来就不是这样设计的。例如,它使用所谓的“共享计数”对象来存储引用计数和删除器,并且该共享计数对象由
shared_ptr
代码分配,因此它不会驻留在共享内存中。此外,shared_ptr代码(以及vtable等元数据)可能位于不同进程中完全不同的地址,因此任何虚拟函数调用也将是一个问题(IIRCshared_ptr使用内部的虚函数 - 或者至少是函数指针,这会导致同样的问题)。我不知道
boost::interprocess::shared_ptr
是否是进程间安全的,但我很确定它不是。进程间同步的开销非常大。如果boost::interprocess::shared_ptr
不执行此操作,则用户可以阻止对共享数据的访问。这样连续多次访问只需支付一次高昂的同步成本。编辑:我希望 Eamon Nerbonne 在他的评论中提到的使用模式(使用
boost::shared_ptr
是线程安全的),也可以使用boost::interprocess::shared_ptr
。但不能肯定地说。Er.
boost::shared_ptr
is most definitely not thread-safe. At least not more thread-safe than e.g.std::vector
. You may read aboost::shared_ptr
from multiple threads, but as soon as any thread is writing aboost::shared_ptr
it must synchronize with other writers and readers.And no, you can not use it in shared memory, it was never designed to be. E.g. it uses a so called "shared count" object that stores the reference-count and the deleter, and that shared-count object is allocated by the
shared_ptr
code, so it will not reside in shared memory. Also theshared_ptr
code (and meta data like vtables) might be at totally different addresses in different processes, so any virtual function call would also be a problem (and IIRCshared_ptr
uses virtual functions internally - or at least function pointers, which leads to the same problem).I don't know if
boost::interprocess::shared_ptr
is interprocess-safe, but I'm pretty sure it's not. Interprocess synchronization is pretty expensive. Havingboost::interprocess::shared_ptr
not do it makes it possible for the user to block accesses to shared data. That way the high synchronization cost only has to be paid once for multiple accesses in a row.EDIT: I would expect that the usage pattern that Eamon Nerbonne refered to in his comment (which is thread-safe with
boost::shared_ptr
), is also OK withboost::interprocess::shared_ptr
. Can't say for sure though.“大多数时候,在 boost::fixed_management_shared_memory 段中使用 boost::interprocess::shared_ptr 似乎是有效的:但并非总是如此。”
如果不总是意味着删除并不总是有效:
只需将信号量与线程安全容器一起使用即可。这个信号量并不能提高线程安全性,但可以验证甚至限制有多少用户使用该数据。如果semaphore为0,则不再有用户,安全删除共享数据。
如果只有一个用户,则该值为 1,因此复制用户请求的数据,删除共享容器,然后返回副本。
"This seems to work, most of the time, using boost::interprocess::shared_ptr in a boost::fixed_managed_shared_memory segment: but not always."
If not always means that deletion don't work always:
Just use a semaphore with your thread safe container. This semaphore is not improve thread safety, but you can verify and even limit how many user use the data. If semaphore is 0, then no more user, safe delete the shared data.
If only one user there, this will be 1, so copy out the user-requested data, delete the shared container, then return with the copy.
查看shared_ptr.hpp中的代码以及boost网站上的文档,似乎取消引用单个实例可能是线程安全的,也可能不是线程安全的,具体取决于第二个模板参数,该参数确定要使用的内部指针类型。具体来说,
“内部指针将与 typename VoidAllocator::pointer 类型具有相同的指针类型(也就是说,如果 typename VoidAllocator::pointer 是 offset_ptr,则内部指针将为 offset_ptr)。”
由于解引用仅返回此类的 get()/get_pointer() 方法的结果,因此它可能应该完全依赖于此。如果您想要同时进行只读访问,Boost::shared_ptr 将起作用。对于来自多个线程的写访问,您可能必须编写自己的以 offset_ptr 为模型的包装器。
Looking through the code in shared_ptr.hpp, and at the docs on the boost website, it would seem as though dereferencing a single instance may or may not be threadsafe depending on the second template parameter, which determines the internal pointer type to be used. Specifically,
"The internal pointer will be of the same pointer type as typename VoidAllocator::pointer type (that is, if typename VoidAllocator::pointer is offset_ptr, the internal pointer will be offset_ptr)."
And since dereferences merely return the result of get()/get_pointer() method of this class, it should probably depend entirely on that. Boost::shared_ptr will work if you want simultaneous read-only access. For write access from multiple threads, you might have to write your own wrapper modelled after offset_ptr.
正如 pgroke 所暗示的(不确定为什么投反对票),核心问题是您是否从不同的线程或进程访问相同的 shared_ptr 实例。
shared_ptr(进程间或非进程间)不支持这种情况,并且这不安全。
另一方面,shared_ptr 被设计为具有多个(线程私有的,或通过某种其他机制防止并发修改)共享指针实例指向同一对象,并且使这些指向同一对象的指针的不同实例可以同时修改,而无需问题。
::interprocess:: 这里主要是一个红鲱鱼 - 它不会改变指针的线程安全性,只是确保没有内部指针引用进程私有内存等。
那么这两种情况中的哪一种是吗?
As pgroke alludes to (not sure why the downvotes) the core question is whether you are accessing the same shared_ptr instance from different threads or processes.
shared_ptr (interprocess or not) does not support this scenario, and this will not be safe.
On the other hand, shared_ptr is designed to have multiple (thread-private, or protected from concurrent modification via some other mechanism) shared pointer instances point to the same object, and have different instances of these pointers to the same object be modified concurrently without issue.
::interprocess:: here is mostly a red-herring - it doesn't change the thread-safety of the pointer, just makes sure there are no internal pointers that refer to process-private memory, etc.
So which of the two cases is it?