1

I have a below code that gives segmentation fault sometime?

vector<int> myvector;
void function1()
{
    for(int i = 0;i<10;i++)
    {
        cout<<"writer thread:"<<i<<endl;
        myvector.push_back(i);
    }
}
void function2()
{
    for(int i = 0;i<10;i++)
    {
        cout<<"reader thread:";
        cout<<myvector[i]<<endl;
    }
}
int main()
{

    thread t1(function1);
    thread t2(function2);

    t1.join();
    t2.join();
}

I am little confused with the thread safe rules/guarantees on containers in general and vectors in particular. I was asked this question in an interview and failed to put in words why it write in on thread and write in other thread is not thread-safe operation.

in the below link for push_back of vectors I see "Otherwise, no existing element is accessed, and concurrently accessing or modifying them is safe" under Data Race section. How does this statement justify that vector write operation is not thread-safe?

http://www.cplusplus.com/reference/vector/vector/push_back/

arjun jawalkar
  • 138
  • 1
  • 10
  • 1
    reading is fine if, and only if, thats the only operation being done. When you start to introduce writing you get race-conditions on read/write operations. Rule of thumb: reading may be done by n threads, writing may be done by 1 thread. But reading and writing may not be done at the same time. – Neijwiert Mar 15 '19 at 14:53
  • Thread safety, just like everything, has a cost. There is no sense, in paying that cost, when such safety is not needed, like it isn't, in the default usage. – Algirdas Preidžius Mar 15 '19 at 14:58

4 Answers4

5

From Scott Meyers, Effective STL, Item 12: "Have realistic expectations about the thread safety of STL containers".

  • Multiple readers are safe. Multiple threads may simultaneously read the contents of a single container, and this will work correctly. Naturally, there must not be any writers acting on the container during the reads.

  • Multiple writers to different containers are safe. Multiple threads may simultaneously write to different containers.

That's all, and let me make clear that this is what you can hope for, not what you can expect.

I think I don't have to provide any additional interpretation here :)

Community
  • 1
  • 1
lubgr
  • 37,368
  • 3
  • 66
  • 117
  • There is a c++ reference website which states as below. http://www.cplusplus.com/reference/vector/vector/push_back/ Data races The container is modified. If a reallocation happens, all contained elements are modified. Otherwise, no existing element is accessed, and concurrently accessing or modifying them is safe. I want to know what does the last sentence mean. I get a feeling that the it means concurrent writing to the vector is thread safe, but isn't it wrong? – arjun jawalkar Mar 16 '19 at 14:54
  • @arjunjawalkar Look above: _Multiple writers to **different** containers are safe._ A `std::vector::push_back()` may cause re-allocation of internal buffer but would change at least the internal size member of `std::vector` instance. To make this thread-safe, that members had to be atomic or otherwise guarded. But then, such safety has costs concerning performance which you had to pay in every single threading usage as well. Hence, it even doesn't make sense to make the writing to `std::vector` thread-safe. – Scheff's Cat Mar 19 '19 at 09:37
  • @arjunjawalkar Btw. I'm not quite sure how I should interprete the last sentence _Otherwise, no existing element is accessed, and concurrently accessing or modifying them is safe._ as well. But, as explained above, I'm really sure that doesn't cover `std::vector::push_back()`. As `push_back()` changes size _and_ might cause re-allocation, the first and second sentence cover this. – Scheff's Cat Mar 19 '19 at 09:40
  • @Scheff Thanks for addressing. I believe that vector read/write has race condition and are not thread-safe. When an interviewer starts arguing that its thread safe even after explaining the underlying reasons, as a job seeker you cannot do anything, as you need to impress the interviewer with your knowledge on language to get shortlisted for fucther process. – arjun jawalkar Mar 20 '19 at 02:39
  • there are situations when concurrent modifications from different threads to the same container are safe: https://stackoverflow.com/a/33618459/3758484 – johnbakers Jun 09 '20 at 18:54
3

That is as unsafe as it gets. Imagine you just run the second thread first, and only than (after it is completed) you start executing the first one. What do you think will your code do?

So even if std::vector was super thread-safe for concurrent access (it is not) the code still would be very wrong.

SergeyA
  • 61,605
  • 5
  • 78
  • 137
  • 1
    there are situations when concurrent modifications from different threads to the same container are safe: https://stackoverflow.com/a/33618459/3758484 – johnbakers Jun 09 '20 at 18:53
2

No, std::vector<> is not thread-safe how you are using it. It is only thread-safe in the following cases:

  1. All threads are only reading from the vector
  2. If one thread writes to the vector, there are no concurrent reading operations.

The Segmentation Fault happens when function2 is running earlier/faster then function1. ``function1I would for example access myvector[4] which wasn't push'ed to the vector. In this case you will get an access-out-of-bonds error and, depending on what the rest of your system is doing, this could lead to reading wrong data or a segmentation fault.

A.K.
  • 861
  • 6
  • 12
2

The rule is: If you have a shared object accessed between threads, and at least one of those threads is a writer, then you need synchronization. Without that you have data race which is undefined behavior.

In your case since you are reading from the vector while you are writing to it, it is definitely not thread safe.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
  • there are situations when concurrent modifications from different threads to the same container are safe: https://stackoverflow.com/a/33618459/3758484 – johnbakers Jun 09 '20 at 18:54
  • @johnbakers Those operations aren't modifying the container, the are accessing an element from the container. Multiple threads modifying that same element still need synchronization. – NathanOliver Jun 09 '20 at 18:56