11

In my program I've some threads running. Each thread gets a pointer to some object (in my program - vector). And each thread modifies the vector.

And sometimes my program fails with a segm-fault. I thought it occurred because thread A begins doing something with the vector while thread B hasn't finished operating with it? Can it be true?

How am I supposed to fix it? Thread synchronization? Or maybe make a flag VectorIsInUse and set this flag to true while operating with it?

Benjamin Loison
  • 3,782
  • 4
  • 16
  • 33
Kolyunya
  • 5,973
  • 7
  • 46
  • 81
  • You most likely need to guard the write operations with mutexes. Note that even if you lock write operations, iterators and references might get invalidated, so there is no totally safe solution. You're better off not performing modifying operations from more than one thread. – juanchopanza Sep 04 '12 at 09:58
  • Hi, a segmentation fault is usually caused by accessing memory that is not reserved by your process. Could it be that you are using something as a pointer that actually isn't a pointer? Otherwise, check this out: http://stackoverflow.com/questions/1099513/threadsafe-vector-class-for-c – konqi Sep 04 '12 at 09:59
  • @juanchopanza - not just the write operations, **all** operations. **Every access** to shared data must be protected. – Pete Becker Sep 04 '12 at 10:43
  • @PeteBecker agreed, and some accesses (e.g. references to elements of the container or iterators) you cannot really protect anyway... – juanchopanza Sep 04 '12 at 10:45

3 Answers3

17

vector, like all STL containers, is not thread-safe. You have to explicitly manage the synchronization yourself. A std::mutex or boost::mutex could be use to synchronize access to the vector.

Do not use a flag as this is not thread-safe:

  • Thread A checks value of isInUse flag and it is false
  • Thread A is suspended
  • Thread B checks value of isInUse flag and it is false
  • Thread B sets isInUse to true
  • Thread B is suspended
  • Thread A is resumed
  • Thread A still thinks isInUse is false and sets it true
  • Thread A and Thread B now both have access to the vector

Note that each thread will have to lock the vector for the entire time it needs to use it. This includes modifying the vector and using the vector's iterators as iterators can become invalidated if the element they refer to is erase() or the vector undergoes an internal reallocation. For example do not:

mtx.lock();
std::vector<std::string>::iterator i = the_vector.begin();
mtx.unlock();

// 'i' can become invalid if the `vector` is modified.
hmjd
  • 120,187
  • 20
  • 207
  • 252
  • Beware though that iterators and references may get invalidated, and you cannot protect against that with mutexes. – juanchopanza Sep 04 '12 at 10:04
  • @juanchopanza, yep. Was still updating. – hmjd Sep 04 '12 at 10:06
  • 1
    Gladly. I completely misread your answer. I saw the code sample and I was like "WHAAA EPIC FAIL!". Then I was like "Oh, wait.". – Puppy Sep 04 '12 at 10:10
  • 1
    In any case, having to explicitly remember to lock the mutex before using the vector is quite unsafe, as nothing prevents accidental mis-use, and nothing prevents the iterators from leaking out. A `concurrent_vector` is much safer. – Puppy Sep 04 '12 at 10:12
  • 1
    @DeadMG, is `concurrent_vector` Microsoft only? – hmjd Sep 04 '12 at 10:14
  • There's also one in TBB, which is basically the same principle. – Puppy Sep 04 '12 at 11:26
4

If you want a container that is safe to use from many threads, you need to use a container that is explicitly designed for the purpose. The interface of the Standard containers is not designed for concurrent mutation or any kind of concurrency, and you cannot just throw a lock at the problem.

You need something like TBB or PPL which has concurrent_vector in it.

Puppy
  • 144,682
  • 38
  • 256
  • 465
1

That's why pretty much every class library that offers threads also has synchronization primitives such as mutexes/locks. You need to setup one of these, and aquire/release the lock around every operation on the shared item (read AND write operations, since you need to prevent reads from occuring during a write too, not just preventing multiple writes happening concurrently).

Christian Stieber
  • 9,954
  • 24
  • 23