0

Assuming, I have std::vector and two threads.

First thread is processing erase function while second thread is in for-loop

Is this situation a thread-safe?

Would second thread keep running or throwing an exception?

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

int main()
{
    std::vector<int> intContainer;

    for ( int index = 0; index <= 100000; ++index){
        intContainer.push_back(index);
    }

    std::thread t1([&](){
        while ( 1 ){
            intContainer.erase( std::find(intContainer.begin(), intContainer.end(), random(1, 100000) ) );
            std::this_thread::sleep_for(std::chrono::milliseconds(500));
        }
    });

    std::thread t2([&] (){
        for ( auto& val : intContainer ){
            std::cout << val << std::endl;
        }   
    });

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

    return 0;
}
개발팡야
  • 163
  • 6
  • 2
    This is not thread safe. This is UB. – freakish Mar 19 '19 at 08:55
  • 1
    Have a look at [this](https://stackoverflow.com/questions/9305315/stdvector-thread-safety-multi-threading) or [this](https://stackoverflow.com/questions/55185230/are-read-from-and-writing-to-vector-thread-safe-operations-in-vector-c/55185366#55185366) thread. – lubgr Mar 19 '19 at 08:55
  • If I don't care whether object in vector get deleted or not so, Would it keep continue for-loop or throw error? – 개발팡야 Mar 19 '19 at 08:57
  • Consider reading through the [Help](https://stackoverflow.com/help) and taking the [Tour](https://stackoverflow.com/tour). Especially consider reading through [How do I ask a good question?](https://stackoverflow.com/help/how-to-ask) and [How to create a Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve). – skratchi.at Mar 19 '19 at 08:57
  • It is not only "not thread safe" it is also UB in the same thread as erasing data from a vector make all iterators invalid! – Klaus Mar 19 '19 at 09:14

1 Answers1

6

It is thread-unsafe, but also undefined behavior.

It is thread-unsafe because you are changing elements (and the vector itself) while you are iterating through it.

It is undefined behavior because of the above point (races), but also because you are erasing elements basically anywhere in the vector, which means you are effectively invalidating all iterators to it (which you are using to iterate in the other thread). So even if this was a single-threaded program (e.g. using fibers), you would still have UB.


Note that exceptions won't be thrown because something isn't thread-safe. That does not mean, of course, that errors (be it corruption, crashes, etc.) won't happen -- they will, with most certainty.

In addition, note that the threads (neither of them) will "stop running" either. They will continue without knowing they are messing up everything. The point is that there is no way for them to know.

Acorn
  • 24,970
  • 5
  • 40
  • 69
  • Edited answer :) – Acorn Mar 19 '19 at 09:22
  • Just a side not, MSVC *might* throw an exception when compiled with `DEBUG` symbol, with message saying *vector iterators incompatible* :-) – Zereges Mar 19 '19 at 09:25
  • It's also undefined behaviour because of the data race – Caleth Mar 19 '19 at 09:28
  • @Zereges Of course, if you are debugging it with some tool, you may be lucky to spot it. This was written w.r.t. the guarantees that the language gives (and anyway, even if a tool could give you such guarantee, code wouldn't be written that way regardless :) – Acorn Mar 19 '19 at 09:35
  • @Caleth Indeed, thanks -- edited a bit to reflect that plus also explained that UB would happen even in a single-thread situation. – Acorn Mar 19 '19 at 09:35