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::interpro
"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.
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?
The reference count used in boost::interprocess:shared_ptr
is implemented using an atomic counter defined in boost/interprocess/detail/atomic.hpp
with the refcount logic mainly implemented by boost/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:
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.
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 different shared_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.
Er. boost::shared_ptr
is most definitely not thread-safe. At least not more thread-safe than e.g. std::vector
. You may read a boost::shared_ptr
from multiple threads, but as soon as any thread is writing a boost::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 the shared_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 IIRC shared_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. Having boost::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 with boost::interprocess::shared_ptr
. Can't say for sure though.
boost::shared_ptr<T>
is not interprocess safe, so whether it is multithread safe in this context is moot. (This statement assumes that BOOST_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 a shared_memory
segment would succeed, and does not appear to be supported functionality by the Boost maintainers.
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.