Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Thread safe vector

Let me start by saying that I have read most SO and other topics on the subject.

The way I understand things, std::vector will reallocate memory when pushing back new items, which is my case, unless I have reserved enough space (which is not my case).

What I have is a vector of std::shared_ptr, and that vector holds unique objects (or more correctly, pointers to unique objects in the vector).

The handling of those objects via pointers is wrapped around a Factory & Handler class, but pointers to the objects are accessible from outside the wrapper class and can have member values modified. There is no deleting happening at any time.

If I am understanding correctly issues raised in previous SO questions about std::vector and thread safety, adding (push_back) new objects may invalidate previous pointers, as the vector internally may reallocate memory and copy everything over, which would of course be a disaster for me.

My intentions are to read from that vector, often modifying objects through the pointers, and add new items to the vector, from threads running asynchronously.

So,

  1. Using atomic or mutexes is not enough? If I push back from one thread, another thread handling an object via pointer may end up having an invalid object?
  2. Is there a library that can handle this form of MT issues? The one I keep reading about is Intel's TBB, but since I'm already using C++11, I'd love to keep changes to a minimum, even if it means more work on my part - I want to learn in the process, not just copy-paste.
  3. Other than locking access while modifying objects, I would want asynchronous parallel read access to the vector that will not be invalidated by push_backs. How can I achieve that?

If it is of any importance, all the above is on linux (debian jessie) using gcc-4.8 with c++11 enabled.

I am open to using minimally invasive libraries.

Many thanks in advance :-)

like image 224
Ælex Avatar asked May 12 '14 23:05

Ælex


People also ask

What is thread-safe in vector?

Vectors are synchronized. Any method that touches the Vector 's contents is thread safe. ArrayList , on the other hand, is unsynchronized, making them, therefore, not thread safe.

Are std :: vectors thread-safe?

const and Thread Safety The C++11 standard does not expect to be able to safely call non const functions simultaneously. Therefore all classes available from the standard, e.g. std::vector<>, can safely be accessed from multiple threads in the same manner.

Is a vector thread-safe Java?

The collection classes that are thread-safe in Java are Stack, Vector, Properties, Hashtable, etc.

Is std::vector Push_back thread-safe?

This operation mutates state and therefore is not const , but the mutation is guaranteed to be atomic, and is therefore thread-safe.


1 Answers

adding (push_back) new objects may invalidate previous pointers ...

No, this operation doesn't invalidate any previous pointers, unless you are refering to addresses inside the vectors internal data management (which clearly isn't your scenario).
If you store raw pointers, or std::shared_ptr's there, those will be simply copied, and not get invalid.


As mentioned in comments a std::vector isn't very suitable to guarantee thread safety for producer / consumer patterns for a number of reasons. Neither storing raw pointers to reference the alive instances is!

A Queue will be much better to support this. As for standards you can use the std::deque to have ceratain access points (front(),back()) for the producer / consumer.

To make these access point's thread safe (for pushing/popping values) you can easily wrap them with your own class and use a mutex along, to secure insertion/deletion operations on the shared queue reference.
The other (and major, as from your question) point is: manage ownership and lifetime of the contained/referenced instances. You may also transfer ownership to the consumer, if that's suitable for your use case (thus getting off from the overhead with e.g. std::unique_ptr), see below ...

Additionally you may have a semaphore (condition variable), to notify the consumer thread, that new data is available.


'1. Using atomic or mutexes is not enough? If I push back from one thread, another thread handling an object via pointer may end up having an invalid object?'

The lifetime (and thus thread safe use) of the instances stored to the queue (shared container) need's to be managed separately (e.g. using smart pointers like std::shared_ptr or std::unique_ptr stored there).

'2. Is there a library ...'

It can be achieved all well with the existing standard library mechanisms IMHO.

As for point 3. see what's written above. As what I can tell further about this, it sounds like you're asking for something like a rw_lock mutex. You may provide a surrogate for this with a suitable condition variable.

Feel free to ask for more clarification ...

like image 143
πάντα ῥεῖ Avatar answered Nov 12 '22 21:11

πάντα ῥεῖ