0

Can a vector be written to by multiple threads without worrying about any potential race conditions between the threads trying to push_back a value at the same time? The underlying hardware/os will take care of everything and ensure theres no potential for the program crashing or failing right?

Just wanted to experiment with a simple example that didnt use locks mutexes or atomics.

#include <iostream>
#include<thread>
#include<vector>

using namespace std;

std::vector<int> myvector;


void append(int value)
{
  myvector.push_back(value);
}


int main()
{

 int val1=1;
 int val2=2;
 int val3=3;

 std::thread t1(append,val1);
 std::thread t2(append,val2);
 std::thread t3(append,val3);

 t1.join();
 t2.join();
 t3.join();



 for(int x=0; x<myvector.size(); ++x)
        std::cout<<myvector[x]<<endl;


 return 0;

}

Running the program many times gives expected results of various combinations of push_backs by the threads

visitor
  • 111
  • 5
  • 3
    Possible duplicate of [Is std::vector or boost::vector thread safe?](https://stackoverflow.com/questions/9042571/is-stdvector-or-boostvector-thread-safe) – CuriouslyRecurringThoughts Jul 26 '19 at 20:59
  • The easy answer is that it is just as safe as you make it. C++ doesn't usually (nearly never) come with much overhead if you don't request it. – Ted Lyngmo Jul 27 '19 at 00:40
  • Would putting a mutex on the function that writes to the vector then ensure that no matter how many threads call the push_back simulateneously each threads call of push_back will be carried out on the vector (regardless of order ) and not "lost"? – visitor Jul 28 '19 at 22:31

2 Answers2

1

Neither std::vector, nor any of the containers in the C++ library are thread-safe. When using any container you will need to use mutexes and condition variables in order to correctly synchronize access to the container between threads.

The shown code is undefined behavior. Repeatedly varying the number of threads, and/or increasing the number of values pushed into a vector by the same thread, and/or otherwise loading the server with other processing loads, should eventually produce a crash or wrong results.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
  • Many thanks for your response, would there be a possibility for the program to just crash because many threads want access to same region in memory? – visitor Jul 26 '19 at 21:03
  • Read-only access by itself will not result in undefined behavior, however there still need to be proper synchronization between threads that modify shared data even if subsequent access is read-only. – Sam Varshavchik Jul 26 '19 at 21:12
1

None of the stl containers are thread safe, but it is easy enough to wrap them with mutexes. The issue is not for multiple reading as such, but when they are written to, it is generally dangerous to perform multiple mutate operations in parallel as internal pointers and counters will not be updated correctly; and it needs great care to read while mutate operations are occurring (potentially) on other threads.

std::vector is a particularly poor choice because the whole object is regularly at risk from resizing, leaving iterators broken even in single threading.

std::list variants are better because the elements are allocated individually, but you still have to put your own exclusion locking around any insert or delete, push or pop. Assuming you have only 1 list popper, if you know separately that last time you did not pop the list empty, then you can read the back without a mutex, before then popping it under a mutex against other threads pushing new elements on the front. If you popped the list empty last time, then you can't safely acquire the front() again without the mutex. In these circumstances you might want to implement a semaphore to awaken the popper thread when new data is added. On the other hand, if you have multiple readers and multiple writers, you can have the readers use a different mutex for getting to be the current popper, and still at least get to read the top without fighting the writers.

On the other hand if you take the simplistic approach of just mutexing all your accesses to the container, then it might as well be vector.

Gem Taylor
  • 5,381
  • 1
  • 9
  • 27
  • Thanks for your response, when many threads try to write to the same variable at once, does the danger arise from losing the integrity of the data rather than the actual program crashing? like there has to be something at the hardware level that prevents concurent writes or something – visitor Jul 26 '19 at 21:22
  • 1
    Ultimately it is the integrity of the data, but the data is also pointers, and bad pointers cause crashes. If two threads try to push() they will both create a record, then try to stitch it into the link list. The pointer value that gets written may or may not include both objects and it could even be a corrupt amalgam of the two addresses. The next attempt to get or pop will read that bad pointer and probably crash. – Gem Taylor Jul 29 '19 at 10:47
  • Many thanks for your informative response, so the mutex prevents such circumstaces from happening. – visitor Jul 29 '19 at 18:47