STL thread safety

I have read that STL in general is not thread safe. There were some cases in which you can get around without locks and atomic.... I was wondering if the following operations will cause problems.

1. Assume a int with initial value '0'. One thread WILL always read the value. Other thread MAY write a value '1'. Here all I care is whether the value is '0' or not. Is this fine without a lock or atomic operation?

2. I have a hashtable <int,vector>. Again one thread WILL always read. The other thread WILL always write. But nothing is over written nor deleted. Is this thread safe.

If any of the above is not safe, what would be the best way to gain maximum performance with less overhead?
I have read that STL in general is not thread safe

If you're referring to the standard library containers, there are several guarantees regarding thread safety, which are usually summarized as "different threads can update different containers" and "different threads can read the same container" (there's also, for example, "different threads can modify different elements of the same container, except for vector<bool>")

Assume a int with initial value '0'. One thread WILL always read the value. Other thread MAY write a value '1'

This is, by definition, a data race, which is a form of undefined behavior. There is no way to predict what will happen if you don't use synchronization. (practical outcome on common platforms is that the value written may or may not be observed by the thread that's reading, but as far as the language is concerned, there are no guarantees)

I have a hashtable <int,vector>. Again one thread WILL always read. The other thread WILL always write. But nothing is over written nor deleted

define "write". By "nothing is over written nor deleted" I am assuming the member function unordered_map::insert() is called? It does not invalidate references to the elements, but it may invalidate all iterators if rehashing is triggered. If you're reading through a reference, you don't have a data race.
Last edited on
Hi Cubbi,

Thank you for the reply. It was very helpful.

"This is, by definition, a data race, which is a form of undefined behavior"

Case 1: I understand that it will lead to data race and lead to undefined behaviors. But what exactly is that "undefined behavior" is the problem. Actually I dont care about the race. ie, Assume T1 writes to memory X and T2 reads from X. I dont care about which occurs first. Once X is one, assume X will stay 1 forever. But the T1 may again write '1' on top (even though it was 1 already). What I want is the guarantee that T2 eventually sees the '1' (if T1 ever wrote 1) and once it sees '1', it should never see '0'.

Case 1.1: This is a (new) modification of the above case. The only difference being, T1 may write any value now. Here all I want is T2 should read the latest values or the one just before. But no other value. Is this guaranteed.

Case 1.2. What if the memory location X in case 1 was not an integer but a structure of size 24 bytes.

Case 2: Yes I would be using unordered_map::insert(). I would be using iterators. Here also order is not a problem for me. if an iterator is invalid I can catch that exception and restart the iterator. Is this be fine? Note
Case 1: The only way to safely guarantee that T2 sees '1' is to put accesses behind a memory barrier (typically a mutex, but std::atomic would work as well).


Case 1.1: No, that is not guaranteed. You need to synchronize. You need a memory barrier.

Case 1.2: Still need a memory barrier

Case 2: Bad iterators do not necessarily throw an exception. If you have iterators that you are hanging onto, you must never insert anything else into the container.... even in a single thread (unless the container explicitly guarantees that it will not invalidate any iterators on insertion). Nevermind the multithreaded issues.
Last edited on
@Disch,

Thank you for the reply.

I think that answers all :)
Topic archived. No new replies allowed.